Merge pull request #262 from Fuzzlemann/master

PR for 4.0.0 (Fuzzlemann) (1)
This commit is contained in:
Rsl1122 2017-08-19 18:19:34 +03:00 committed by GitHub
commit 25bdd2161e
20 changed files with 285 additions and 111 deletions

View File

@ -77,7 +77,6 @@ public class Log {
* @param messages All messages to add to the debug log.
* @return full debug complex so far.
*/
@SafeVarargs
public static DebugInfo debug(String task, String... messages) {
DebugInfo debug = getDebug(task);
long time = MiscUtils.getTime();

View File

@ -9,14 +9,11 @@ import com.djrapitops.plugin.task.AbsRunnable;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Permissions;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.command.ConditionUtils;
import main.java.com.djrapitops.plan.data.cache.AnalysisCacheHandler;
import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.ui.text.TextUI;
import main.java.com.djrapitops.plan.utilities.Check;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import org.bukkit.ChatColor;
@ -95,52 +92,4 @@ public class AnalyzeCommand extends SubCommand {
analysisCache.sendAnalysisMessage(sender);
}
}
private void runMessageSenderTask(ISender sender) {
plugin.getRunnableFactory().createNew("AnalysisMessageSenderTask", new AbsRunnable() {
private int timesRun = 0;
@Override
public void run() {
timesRun++;
if (analysisCache.isCached() && (!analysisCache.isAnalysisBeingRun() || !analysisCache.isAnalysisEnabled())) {
sendAnalysisMessage(sender);
this.cancel();
return;
}
if (timesRun > 10) {
Log.debug("Command Timeout Message, Analysis.");
sender.sendMessage(Locale.get(Msg.CMD_FAIL_TIMEOUT).parse("Analysis"));
this.cancel();
}
}
}).runTaskTimer(TimeAmount.SECOND.ticks(), 5 * TimeAmount.SECOND.ticks());
}
/**
* Used to send the message after /plan analysis.
* <p>
* Final because
*
* @param sender Command sender.
*/
private void sendAnalysisMessage(ISender sender) {
boolean textUI = Settings.USE_ALTERNATIVE_UI.isTrue();
sender.sendMessage(Locale.get(Msg.CMD_HEADER_ANALYZE).toString());
if (textUI) {
sender.sendMessage(TextUI.getAnalysisMessages());
} else {
// Link
String url = HtmlUtils.getServerAnalysisUrlWithProtocol();
String message = Locale.get(Msg.CMD_INFO_LINK).toString();
boolean console = !CommandUtils.isPlayer(sender);
if (console) {
sender.sendMessage(message + url);
} else {
sender.sendMessage(message);
sender.sendLink(" ", Locale.get(Msg.CMD_INFO_CLICK_ME).toString(), url);
}
}
sender.sendMessage(Locale.get(Msg.CMD_CONSTANT_FOOTER).toString());
}
}

View File

@ -64,9 +64,7 @@ public class AnalysisCacheHandler {
cache = data;
for (UUID uuid : notifyWhenCached) {
Optional<IPlayer> player = plugin.fetch().getPlayer(uuid);
if (player.isPresent()) {
sendAnalysisMessage(player.get());
}
player.ifPresent(this::sendAnalysisMessage);
}
notifyWhenCached.clear();
}

View File

@ -5,6 +5,7 @@ import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.database.Database;
import main.java.com.djrapitops.plan.ui.webserver.response.InspectPageResponse;
import main.java.com.djrapitops.plan.ui.webserver.response.api.JsonResponse;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
import main.java.com.djrapitops.plan.utilities.analysis.ExportUtility;
@ -46,9 +47,13 @@ public class InspectCacheHandler {
*/
public void cache(UUID uuid) {
DBCallableProcessor cacher = data -> {
cache.put(uuid, new UserData(data));
UserData userData = new UserData(data);
cache.put(uuid, userData);
cacheTimes.put(uuid, MiscUtils.getTime());
PageCacheHandler.cachePage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(Plan.getInstance().getUiServer().getDataReqHandler(), uuid));
PageCacheHandler.cachePage("inspectPage: " + uuid, () -> new InspectPageResponse(Plan.getInstance().getUiServer().getDataReqHandler(), uuid));
PageCacheHandler.cachePage("inspectionJson: " + uuid, () -> new JsonResponse(userData));
try {
ExportUtility.writeInspectHtml(data, ExportUtility.getPlayersFolder(ExportUtility.getFolder()), HtmlUtils.getStringFromResource("player.html"));

View File

@ -44,7 +44,7 @@ public class PageCacheHandler {
* @return The Response that was cached or created by the {@link PageLoader loader}
*/
public static Response loadPage(String identifier, PageLoader loader) {
Response response = pageCache.getIfPresent(identifier);
Response response = loadPage(identifier);
if (response != null) {
return response;
@ -57,6 +57,16 @@ public class PageCacheHandler {
return response;
}
/**
* Loads the page from the page cache.
*
* @param identifier The identifier of the page
* @return The Response that was cached or {@code null} if it wasn't
*/
public static Response loadPage(String identifier) {
return pageCache.getIfPresent(identifier);
}
/**
* Puts the page into the page cache.
* <p>

View File

@ -43,20 +43,20 @@ public class PlanCommandPreprocessListener implements Listener {
return;
}
String commandName = event.getMessage().split(" ")[0].toLowerCase();
String commandName = event.getMessage().substring(1).split(" ")[0].toLowerCase();
boolean doNotLogUnknownCommands = Settings.DO_NOT_LOG_UNKNOWN_COMMANDS.isTrue();
boolean combineCommandAliasesToMainCommand = Settings.COMBINE_COMMAND_ALIASES_TO_MAIN_COMMAND.isTrue();
if (doNotLogUnknownCommands || combineCommandAliasesToMainCommand) {
Command command = plugin.getServer().getPluginCommand(commandName.substring(1, commandName.length()));
Command command = plugin.getServer().getPluginCommand(commandName);
if (command == null) {
if (doNotLogUnknownCommands) {
Log.debug("Ignored command, command is unknown");
return;
}
} else if (combineCommandAliasesToMainCommand) {
commandName = "/" + command.getName();
commandName = command.getName();
}
}

View File

@ -27,11 +27,11 @@ public class Select extends SqlParser {
public Select where(String... conditions) {
append(" WHERE ");
for (int i = 0; i < conditions.length; i++) {
for (String condition : conditions) {
if (this.conditions > 0) {
append(" AND ");
}
append("(").append(conditions[i]).append(")");
append("(").append(condition).append(")");
this.conditions++;
}
return this;

View File

@ -66,9 +66,14 @@ public class PlayersTableCreator {
}
private static String getActivityString(boolean isBanned, boolean isUnknown, boolean isActive) {
return isBanned ? "Banned"
: (isUnknown ? "Unknown"
: (isActive ? "Active"
: "Inactive"));
if (isBanned) {
return "Banned";
}
if (isUnknown) {
return "Unknown";
}
return isActive ? "Active" : "Inactive";
}
}

View File

@ -5,6 +5,7 @@ import com.sun.net.httpserver.*;
import main.java.com.djrapitops.plan.Log;
import main.java.com.djrapitops.plan.Plan;
import main.java.com.djrapitops.plan.Settings;
import main.java.com.djrapitops.plan.data.UserData;
import main.java.com.djrapitops.plan.data.WebUser;
import main.java.com.djrapitops.plan.data.cache.PageCacheHandler;
import main.java.com.djrapitops.plan.database.tables.SecurityTable;
@ -12,11 +13,15 @@ import main.java.com.djrapitops.plan.locale.Locale;
import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.ui.html.DataRequestHandler;
import main.java.com.djrapitops.plan.ui.webserver.response.*;
import main.java.com.djrapitops.plan.ui.webserver.response.api.BadRequestResponse;
import main.java.com.djrapitops.plan.ui.webserver.response.api.JsonResponse;
import main.java.com.djrapitops.plan.ui.webserver.response.api.SuccessResponse;
import main.java.com.djrapitops.plan.utilities.Benchmark;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.PassEncryptUtil;
import main.java.com.djrapitops.plan.utilities.uuid.UUIDUtility;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.FileConfiguration;
import javax.net.ssl.*;
import java.io.*;
@ -26,9 +31,7 @@ import java.nio.file.Paths;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Base64;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -84,11 +87,30 @@ public class WebServer {
@Override
public void handle(HttpExchange exchange) throws IOException {
try {
Headers responseHeaders = exchange.getResponseHeaders();
URI uri = exchange.getRequestURI();
String target = uri.toString();
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/html;");
boolean apiRequest = "POST".equals(exchange.getRequestMethod());
Response response = null;
String type = "text/html;";
if (apiRequest) {
response = getAPIResponse(target, exchange);
if (response instanceof JsonResponse) {
type = "application/json;";
}
}
responseHeaders.set("Content-Type", type);
if (apiRequest) {
sendData(responseHeaders, exchange, response);
return;
}
WebUser user = null;
if (usingHttps) {
@ -100,21 +122,9 @@ public class WebServer {
}
}
responseHeaders.set("Content-Encoding", "gzip");
response = getResponse(target, user);
Response response = getResponse(target, user);
String content = response.getContent();
exchange.sendResponseHeaders(response.getCode(), 0);
try (GZIPOutputStream out = new GZIPOutputStream(exchange.getResponseBody());
ByteArrayInputStream bis = new ByteArrayInputStream(content.getBytes())) {
byte[] buffer = new byte[2048];
int count;
while ((count = bis.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
}
sendData(responseHeaders, exchange, response);
} catch (Exception e) {
Log.toLog(this.getClass().getName(), e);
throw e;
@ -136,6 +146,20 @@ public class WebServer {
}
}
private void sendData(Headers header, HttpExchange exchange, Response response) throws IOException {
header.set("Content-Encoding", "gzip");
exchange.sendResponseHeaders(response.getCode(), 0);
try (GZIPOutputStream out = new GZIPOutputStream(exchange.getResponseBody());
ByteArrayInputStream bis = new ByteArrayInputStream(response.getContent().getBytes())) {
byte[] buffer = new byte[2048];
int count;
while ((count = bis.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
}
}
private WebUser getUser(Headers requestHeaders) {
Benchmark.start("getUser");
try {
@ -243,6 +267,137 @@ public class WebServer {
return startSuccessful;
}
private String readPOSTRequest(HttpExchange exchange) throws IOException {
try (InputStream in = exchange.getRequestBody()) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte buf[] = new byte[4096];
for (int n = in.read(buf); n > 0; n = in.read(buf)) {
out.write(buf, 0, n);
}
return new String(out.toByteArray(), "ISO-8859-1");
}
}
private Response getAPIResponse(String target, HttpExchange exchange) throws IOException {
String[] args = target.split("/");
if (args.length < 3) {
String error = "API Method not specified";
return PageCacheHandler.loadPage(error, () -> new NotFoundResponse(error));
}
String method = args[2];
String response = readPOSTRequest(exchange);
Map<String, String> variables = readVariables(response);
//TODO ADD CHECK IF SERVER KEY VALID
Plan plan = Plan.getInstance();
String playerString;
UUID uuid;
String identifier;
switch (method) {
//TODO Add Bungee APIs
case "analyze":
plan.getAnalysisCache().updateCache();
return PageCacheHandler.loadPage("success", SuccessResponse::new);
case "inspect":
playerString = variables.get("player");
if (playerString == null) {
String error = "Player String not included";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
uuid = UUIDUtility.getUUIDOf(playerString);
if (uuid == null) {
String error = "UUID not found";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
Plan.getInstance().getInspectCache().cache(uuid);
return PageCacheHandler.loadPage("success", SuccessResponse::new);
case "analysis":
case "analytics":
identifier = "analysisJson";
if (!PageCacheHandler.isCached(identifier)) {
return PageCacheHandler.loadPage("No Analysis Data", () -> new BadRequestResponse("No analysis data available"));
}
return PageCacheHandler.loadPage(identifier);
case "inspection":
playerString = variables.get("player");
if (playerString == null) {
String error = "Player String not included";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
uuid = UUIDUtility.getUUIDOf(playerString);
if (uuid == null) {
String error = "UUID not found";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
UserData userData = plan.getInspectCache().getFromCache(uuid);
if (userData == null) {
String error = "User not cached";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
return PageCacheHandler.loadPage("inspectionJson: " + uuid, () -> new JsonResponse(plan.getInspectCache().getFromCache(uuid)));
case "configure":
String key = variables.get("configKey");
if (key == null) {
String error = "Config Key null";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
String value = variables.get("configValue");
if (value == null) {
String error = "Config Value null";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
if (value.equals("null")) {
value = null;
}
FileConfiguration config = plan.getConfig();
config.set(key, value);
plan.saveConfig();
return PageCacheHandler.loadPage("success", SuccessResponse::new);
default:
String error = "API Method not found";
return PageCacheHandler.loadPage(error, () -> new BadRequestResponse(error));
}
}
private Map<String, String> readVariables(String response) {
Map<String, String> variableMap = new HashMap<>();
String[] variables = response.split("&");
for (String variable : variables) {
String[] splittedVariables = variable.split("=", 2);
if (splittedVariables.length != 2) {
continue;
}
variableMap.put(splittedVariables[0], splittedVariables[1]);
}
return variableMap;
}
private Response getResponse(String target, WebUser user) {
if ("/favicon.ico".equals(target)) {
return PageCacheHandler.loadPage("Redirect: favicon", () -> new RedirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico"));
@ -259,6 +414,7 @@ public class WebServer {
return forbiddenResponse(permLevel, required);
}
}
String[] args = target.split("/");
if (args.length < 2) {
return rootPageResponse(user);
@ -294,6 +450,7 @@ public class WebServer {
if (user == null) {
return notFoundResponse();
}
switch (user.getPermLevel()) {
case 0:
return serverResponse();
@ -333,7 +490,7 @@ public class WebServer {
return PageCacheHandler.loadPage("notFound: " + error, () -> new NotFoundResponse(error));
}
return PageCacheHandler.loadPage("inspectPage: " + uuid.toString(), () -> new InspectPageResponse(dataReqHandler, uuid));
return PageCacheHandler.loadPage("inspectPage: " + uuid, () -> new InspectPageResponse(dataReqHandler, uuid));
}
private Response notFoundResponse() {

View File

@ -0,0 +1,18 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan.ui.webserver.response.api;
import main.java.com.djrapitops.plan.ui.webserver.response.Response;
/**
* @author Fuzzlemann
*/
public class BadRequestResponse extends Response {
public BadRequestResponse(String error) {
super.setHeader("HTTP/1.1 400 Bad Request");
super.setContent(error);
}
}

View File

@ -0,0 +1,21 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan.ui.webserver.response.api;
import com.google.gson.Gson;
import main.java.com.djrapitops.plan.ui.webserver.response.Response;
/**
* @author Fuzzlemann
*/
public class JsonResponse extends Response {
public <T> JsonResponse(T object) {
Gson gson = new Gson();
super.setHeader("HTTP/1.1 200 OK");
super.setContent(gson.toJson(object));
}
}

View File

@ -0,0 +1,18 @@
/*
* Licence is provided in the jar as license.yml also here:
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
*/
package main.java.com.djrapitops.plan.ui.webserver.response.api;
import main.java.com.djrapitops.plan.ui.webserver.response.Response;
/**
* @author Fuzzlemann
*/
public class SuccessResponse extends Response {
public SuccessResponse() {
super.setHeader("HTTP/1.1 200 OK");
super.setContent("Success");
}
}

View File

@ -20,6 +20,7 @@ import main.java.com.djrapitops.plan.locale.Msg;
import main.java.com.djrapitops.plan.ui.html.tables.PlayersTableCreator;
import main.java.com.djrapitops.plan.ui.webserver.response.AnalysisPageResponse;
import main.java.com.djrapitops.plan.ui.webserver.response.PlayersPageResponse;
import main.java.com.djrapitops.plan.ui.webserver.response.api.JsonResponse;
import main.java.com.djrapitops.plan.utilities.Benchmark;
import main.java.com.djrapitops.plan.utilities.HtmlUtils;
import main.java.com.djrapitops.plan.utilities.MiscUtils;
@ -165,8 +166,9 @@ public class Analysis {
Log.info(Locale.get(Msg.ANALYSIS_FINISHED).parse(String.valueOf(time), HtmlUtils.getServerAnalysisUrlWithProtocol()));
}
PageCacheHandler.removeIf(identifier -> identifier.startsWith("inspectPage: "));
PageCacheHandler.removeIf(identifier -> identifier.startsWith("inspectPage: ") || identifier.startsWith("inspectionJson: "));
PageCacheHandler.cachePage("analysisPage", () -> new AnalysisPageResponse(plugin.getUiServer().getDataReqHandler()));
PageCacheHandler.cachePage("analysisJson", () -> new JsonResponse(analysisData));
PageCacheHandler.cachePage("players", () -> new PlayersPageResponse(plugin));
ExportUtility.export(analysisData, rawData);

View File

@ -18,8 +18,7 @@ public class DumpLog {
* @param header The name of the header
*/
public void addHeader(String header) {
addLine("");
addLine("--- " + header + " ---");
addLines("", "--- " + header + " ---");
}
/**

View File

@ -145,7 +145,7 @@ public class DumpUtils {
List<String> plugins = Arrays.stream(server.getPluginManager().getPlugins())
.map(Plugin::getDescription)
.map(description -> description.getName() + " " + description.getVersion())
.sorted()
.sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());
log.addHeader("Server Details");

View File

@ -74,5 +74,4 @@ public class SettingsTest {
public void testGetPath() {
assertEquals("Settings.WebServer.Enabled", Settings.WEBSERVER_ENABLED.getPath());
}
}

View File

@ -106,14 +106,11 @@ public class DataCacheQueueTest {
public void testGetQueue_cache() {
List<Integer> calls = new ArrayList<>();
List<Integer> errors = new ArrayList<>();
handler.getUserDataForProcessing(new DBCallableProcessor() {
@Override
public void process(UserData data) {
if (data.equals(data1)) {
calls.add(1);
} else {
errors.add(1);
}
handler.getUserDataForProcessing(data -> {
if (data.equals(data1)) {
calls.add(1);
} else {
errors.add(1);
}
}, uuid1);
while (calls.size() < 1) {
@ -131,14 +128,11 @@ public class DataCacheQueueTest {
public void testGetQueue_dontCache() {
List<Integer> getCalls = new ArrayList<>();
List<Integer> errors = new ArrayList<>();
handler.getUserDataForProcessing(new DBCallableProcessor() {
@Override
public void process(UserData data) {
if (data.equals(data1)) {
getCalls.add(1);
} else {
errors.add(1);
}
handler.getUserDataForProcessing(data -> {
if (data.equals(data1)) {
getCalls.add(1);
} else {
errors.add(1);
}
}, uuid1, false);
while (getCalls.size() < 1) {

View File

@ -10,6 +10,7 @@ import org.junit.Test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@ -46,7 +47,7 @@ public class MathUtilsTest {
*/
@Test
public void testAverageIntEmpty() {
List<Integer> l = new ArrayList<>();
List<Integer> l = Collections.emptyList();
double exp = 0;
double result = MathUtils.averageInt(l.stream());
assertTrue(result + "/" + exp, Double.compare(exp, result) == 0);

View File

@ -46,7 +46,6 @@ public class HastebinTest {
/* Ignored */
}
Log.info(link);
testLink.set(link);
});

View File

@ -139,7 +139,7 @@ public class TestInit {
@Override
public ITask runTask() {
new Thread(() -> runnable.run()).start();
new Thread(runnable::run).start();
return null;
}