From 3769c303fbbf846f32b088468969efd6a4631dba Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Tue, 25 Jul 2017 11:27:08 +0300 Subject: [PATCH] Fix webserver being unable to respond due to open socket -> endless inputstream. (Introduced in 7e03c1dcc03d343ab533a50791d4cb1c608c5644) Fix #179 Attempts to use scatter graph for inspect page, code still needs refining. --- .../graphs/PlayerActivityGraphCreator.java | 96 +- .../plan/ui/html/graphs/TPSGraphCreator.java | 29 +- .../djrapitops/plan/ui/webserver/Request.java | 21 +- .../plan/ui/webserver/WebSocketServer.java | 2 +- .../plan/ui/webserver/response/Response.java | 1 + .../plan/utilities/PlaceholderUtils.java | 6 +- Plan/src/main/resources/analysis.html | 1063 +++++++++-------- Plan/src/main/resources/player.html | 542 +++++---- .../PlayerActivityGraphCreatorTest.java | 26 +- 9 files changed, 894 insertions(+), 892 deletions(-) diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java index a3977f3e2..8a37a23f6 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/PlayerActivityGraphCreator.java @@ -1,47 +1,29 @@ package main.java.com.djrapitops.plan.ui.html.graphs; -import main.java.com.djrapitops.plan.Plan; -import main.java.com.djrapitops.plan.Settings; import main.java.com.djrapitops.plan.data.SessionData; import main.java.com.djrapitops.plan.data.TPS; -import main.java.com.djrapitops.plan.utilities.FormatUtils; import main.java.com.djrapitops.plan.utilities.MiscUtils; -import main.java.com.djrapitops.plan.utilities.analysis.MathUtils; import main.java.com.djrapitops.plan.utilities.analysis.Point; -import java.io.Serializable; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; /** - * * @author Rsl1122 */ public class PlayerActivityGraphCreator { - @Deprecated - public static String[] generateArray(List tpsData, long scale) { - long now = MiscUtils.getTime(); - List filtered = tpsData.stream().filter(tps -> tps.getDate() >= now - scale).collect(Collectors.toList()); - String players = filtered.stream().map(TPS::getPlayers).collect(Collectors.toList()).toString(); - String dates = filtered.stream().map(TPS::getDate).collect(Collectors.toList()).toString(); - return new String[]{players, dates}; - } - public static String buildScatterDataString(List tpsData, long scale) { long now = MiscUtils.getTime(); - List points = tpsData.stream().filter(tps -> tps.getDate() >= now - scale).map(tps -> new Point(tps.getDate(), tps.getPlayers())).collect(Collectors.toList()); + List points = tpsData.stream() + .filter(tps -> tps.getDate() >= now - scale) + .map(tps -> new Point(tps.getDate(), tps.getPlayers())) + .collect(Collectors.toList()); return ScatterGraphCreator.scatterGraph(points, true); } - /** - * - * @param sessionData - * @param scale - * @return - */ - public static String[] generateDataArray(List sessionData, long scale) { + public static String buildScatterDataStringSessions(List sessionData, long scale) { long now = MiscUtils.getTime(); long nowMinusScale = now - scale; List> s = filterAndTransformSessions(sessionData, nowMinusScale); @@ -53,52 +35,26 @@ public class PlayerActivityGraphCreator { sessionStarts.add(nowMinusScale); } - Map change = transformIntoChangeMap(sessionStarts, sessionEnds); - - long lastPValue = 0; - long lastSavedPValue = -1; - long lastSaveIndex = 0; - List playersOnline = new ArrayList<>(); - List labels = new ArrayList<>(); - for (long i = nowMinusScale / 1000; i <= now / 1000; i += 1) { - long index = i * 1000; - boolean contains = change.containsKey(index); - boolean isBelowMinimumScaleThreshold = index - lastSaveIndex > (scale / (long) 75); - if (!(contains || isBelowMinimumScaleThreshold)) { - continue; - } - if (contains) { - lastPValue += change.get(index); - } - if (isBelowMinimumScaleThreshold || lastSavedPValue != lastPValue) { - lastSaveIndex = index; - labels.add("\"" + FormatUtils.formatTimeStamp(index) + "\""); - lastSavedPValue = lastPValue; - playersOnline.add(lastPValue); - } - } - if (Settings.ANALYSIS_REMOVE_OUTLIERS.isTrue()) { - long average = MathUtils.averageLong(playersOnline.stream()); - double standardDeviation = getStandardDeviation(playersOnline, average); - if (standardDeviation > 3.5) { - for (int i = 0; i < playersOnline.size(); i++) { - long value = playersOnline.get(i); - if (value - average > 3 * standardDeviation) { - playersOnline.set(i, (long) Plan.getInstance().getVariable().getMaxPlayers() + 10); - } - } - } - } - return new String[]{playersOnline.toString(), labels.toString()}; + Map changeMap = transformIntoChangeMap(sessionStarts, sessionEnds); + List points = getPointsFromChangeMap(changeMap); + return ScatterGraphCreator.scatterGraph(points, false); } - private static double getStandardDeviation(List players, long avg) { - List valueMinusAvg = players.stream() - .map(p -> Math.pow(Math.abs(p - avg), 2)) - .collect(Collectors.toList()); - int size = valueMinusAvg.size(); - double sum = MathUtils.sumDouble(valueMinusAvg.stream().map(p -> (Serializable) p)); - return Math.sqrt(sum / size); + private static List getPointsFromChangeMap(Map changeMap) { + List points = new ArrayList<>(); + int lastIndex = -1; + for (Long key : changeMap.keySet()) { + long date = key; + int change = changeMap.get(key); + if (change != 0) { + int previousValue = 0; + if (lastIndex >= 0) { + previousValue = (int) points.get(lastIndex).getY(); + } + points.add(new Point(date, previousValue+change)); + } + } + return points; } private static Map transformIntoChangeMap(List sessionStarts, List sessionEnds) { @@ -121,20 +77,15 @@ public class PlayerActivityGraphCreator { } /** - * * @param values * @param lookFor * @return */ public static long getCount(List values, long lookFor) { return Collections.frequency(values, lookFor); -// values.stream() -// .filter((start) -> (start == lookFor)) -// .count(); } /** - * * @param sessionData * @param nowMinusScale * @return @@ -162,7 +113,6 @@ public class PlayerActivityGraphCreator { } /** - * * @param ms * @return */ diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java index a09ba4995..f47412dbb 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/html/graphs/TPSGraphCreator.java @@ -1,14 +1,13 @@ package main.java.com.djrapitops.plan.ui.html.graphs; +import main.java.com.djrapitops.plan.data.TPS; +import main.java.com.djrapitops.plan.utilities.FormatUtils; +import main.java.com.djrapitops.plan.utilities.MiscUtils; +import main.java.com.djrapitops.plan.utilities.analysis.Point; + import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import main.java.com.djrapitops.plan.Log; -import main.java.com.djrapitops.plan.data.TPS; -import main.java.com.djrapitops.plan.utilities.Benchmark; -import main.java.com.djrapitops.plan.utilities.MiscUtils; -import main.java.com.djrapitops.plan.utilities.analysis.Point; -import main.java.com.djrapitops.plan.utilities.comparators.TPSComparator; /** * @@ -17,22 +16,12 @@ import main.java.com.djrapitops.plan.utilities.comparators.TPSComparator; */ public class TPSGraphCreator { - public static String[] generateDataArray(List tpsData, long scale) { - Benchmark.start("TPSGraph: generate array"); - long now = MiscUtils.getTime(); - List filtered = filterTPS(tpsData, now - scale); - Log.debug("TPSGraph, filtered: " + filtered.size()); - filtered.sort(new TPSComparator()); - List dates = filtered.stream().map(TPS::getDate).collect(Collectors.toList()); - List tps = filtered.stream().map(TPS::getTps).collect(Collectors.toList()); - List players = filtered.stream().map(TPS::getPlayers).collect(Collectors.toList()); - Benchmark.stop("TPSGraph: generate array"); - return new String[]{dates.toString(), tps.toString(), players.toString()}; - } - public static String buildScatterDataStringTPS(List tpsData, long scale) { long now = MiscUtils.getTime(); - List points = tpsData.stream().filter(tps -> tps.getDate() >= now - scale).map(tps -> new Point(tps.getDate(), tps.getTps())).collect(Collectors.toList()); + List points = tpsData.stream() + .filter(tps -> tps.getDate() >= now - scale) + .map(tps -> new Point(tps.getDate(), Double.parseDouble(FormatUtils.cutDecimals(tps.getTps()).replace(",", ".")))) + .collect(Collectors.toList()); return ScatterGraphCreator.scatterGraph(points, true); } diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java index de4ebcced..be42d1d0e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/Request.java @@ -8,12 +8,12 @@ import java.util.Optional; /** * Represents a HTTP Request. - * + *

* Request is read from the given InputStream. - * + *

* Closing the Request closes the InputStream. (Closing Socket InputStream * closes the socket.) - * + *

* Request Strings should not be logged because they may contain base64 encoded * user:password Authorization combinations. * @@ -40,11 +40,11 @@ public class Request implements Closeable { /** * Reads the information in the Request and parses required information. - * + *

* Parses Request (GET, POST etc.) - * + *

* Parses Target (/home/etc) - * + *

* Parses Authorization (Authorization header). * * @throws java.io.IOException if InputStream can not be read. @@ -53,8 +53,11 @@ public class Request implements Closeable { StringBuilder headerB = new StringBuilder(); BufferedReader in = new BufferedReader(new InputStreamReader(input)); close = in; - String line; - while ((line = in.readLine()) != null) { + while (true) { + String line = in.readLine(); + if (line == null || line.isEmpty()) { + break; + } headerB.append(line); headerB.append(":::"); } @@ -126,7 +129,7 @@ public class Request implements Closeable { /** * Closes the Request. - * + *

* Closes the InputStream. * * @throws IOException if the stream can not be closed. diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java index b5da5a49e..2094fda51 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/WebSocketServer.java @@ -92,8 +92,8 @@ public class WebSocketServer { response.sendStaticResource(); } catch (IOException | IllegalArgumentException e) { } finally { - Benchmark.stop("Webserver Response"); MiscUtils.close(input, request, output, socket); + Benchmark.stop("Webserver Response"); } } this.cancel(); diff --git a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java index c8f08803a..6002654ba 100644 --- a/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java +++ b/Plan/src/main/java/com/djrapitops/plan/ui/webserver/response/Response.java @@ -37,6 +37,7 @@ public abstract class Response { + content; // Log.debug("Response: " + response); // Responses should not be logged, html content large. output.write(response.getBytes()); + output.flush(); } public void setHeader(String header) { diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java b/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java index 76cbd8ae3..c708f9cd5 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/PlaceholderUtils.java @@ -1,5 +1,6 @@ package main.java.com.djrapitops.plan.utilities; +import com.djrapitops.plugin.api.TimeAmount; import main.java.com.djrapitops.plan.Plan; import main.java.com.djrapitops.plan.Settings; import main.java.com.djrapitops.plan.data.AnalysisData; @@ -106,10 +107,9 @@ public class PlaceholderUtils { Plan plugin = Plan.getInstance(); replaceMap.put("%version%", plugin.getDescription().getVersion()); replaceMap.put("%planlite%", ""); - String[] playersDataArray = PlayerActivityGraphCreator.generateDataArray(data.getSessions(), (long) 604800 * 1000); replaceMap.put("%graphmaxplayers%", 2 + ""); - replaceMap.put("%dataweek%", playersDataArray[0]); - replaceMap.put("%labelsweek%", playersDataArray[1]); + String scatterGraphData = PlayerActivityGraphCreator.buildScatterDataStringSessions(data.getSessions(), TimeAmount.WEEK.ms()); + replaceMap.put("%dataweek%", scatterGraphData); replaceMap.put("%playersgraphcolor%", Settings.HCOLOR_ACT_ONL + ""); replaceMap.put("%playersgraphfill%", Settings.HCOLOR_ACT_ONL_FILL + ""); replaceMap.put("%datapunchcard%", PunchCardGraphCreator.generateDataArray(data.getSessions())); diff --git a/Plan/src/main/resources/analysis.html b/Plan/src/main/resources/analysis.html index 31d5f788f..57baf7623 100644 --- a/Plan/src/main/resources/analysis.html +++ b/Plan/src/main/resources/analysis.html @@ -1,14 +1,14 @@ - - Plan | Server Analysis - - - - - - - - - -

-
- Player Analytics | Analysis -

Player Analytics v.%version%

-

%servername% | Server Analysis

-
-
-
- -
-
-
-
-
-
-
-
Player Activity - Last 24h
-
-
-
- -
-
-
- %npday% -
-
- New Players -
-
-
-
- -

Unique Players: %uniquejoinsday% | Unique/Day: %avguniquejoinsday%

+ + + +
+
+ Player Analytics | Analysis +

Player Analytics v.%version%

+

%servername% | Server Analysis

+
+
+
+ + +
+
+
+
+
+
+
+
Player Activity - Last 24h
-
-

Recent Logins

-
- %recentlogins% +
+
+ +
+
+
+ %npday% +
+
+ New Players +
-
-
-
-
-
Information
-
-
-
- -
-
-
- %activitytotal% -
-
- Total Players -
-
-
-
-

Total Playtime: %totalplaytime% | Player Average: %avgplaytime%
- Average Session Length: %sessionaverage%
- Total Login times: %totallogins%
- Average Unique Players/Day: %avguniquejoins%
- Player kills: %playerkills% | Mob kills: %mobkills% | Deaths: %deaths%

-
-
-

Gamemode Usage


-
-
-
- -
-
-
- %gm0% -
-
- Survival -
-
-
-
-
- -
-
-
- %gm1% -
-
- Creative -
-
-
-
-
- -
-
-
- %gm2% -
-
- Adventure -
-
-
-
-
- -
-
-
- %gm3% -
-
- Spectator -
-
-
-
- -
+ +

Unique Players: %uniquejoinsday% | Unique/Day: %avguniquejoinsday%

+
+
+

Recent Logins

+
+ %recentlogins%
-
-
-
-
-
-
Player Activity - Last 24h
-
-
-
- -
-
-
- %npday% -
-
- New Players -
-
-
-
- -

Unique Players: %uniquejoinsday% | Unique/Day: %avguniquejoinsday%

+
+
+
+
+
+
Information
-
-
-
-
Player Activity - Last 7d
-
-
-
- -
-
-
- %npweek% -
-
- New Players -
-
-
+
+
+
- -

Unique Players: %uniquejoinsweek% | Unique/Day: %avguniquejoinsweek%

-
-
-
-
-
Player Activity - Last 30d
+
+
+ %activitytotal%
-
-
- -
-
-
- %npmonth% -
-
- New Players -
-
+
+ Total Players
- -

Unique Players: %uniquejoinsmonth% | Unique/Day: %avguniquejoinsmonth%

-
-
-
-
-
-
-
Playerbase Composition
-
-
-
- -
-
-
- %activitytotal% -
-
- Total Players -
-
-
-
-
-
-
- -
-
-
- %active% -
-
- __Active -
-
-
-
-
- -
-
-
- %inactive% -
-
- Inactive -
-
-
-
-
- -
-
-
- %joinleaver% -
-
- Single_join -
-
-
-
-
- -
-
-
- %banned% -
-
- Banned -
-
-
-


-
-
-
-

Recent Logins

-
- %recentlogins% -
+

Total Playtime: %totalplaytime% | Player Average: %avgplaytime%
+ Average Session Length: + %sessionaverage%
+ Total Login times: + %totallogins%
+ Average Unique Players/Day: + %avguniquejoins%
+ Player kills: %playerkills% | Mob kills: %mobkills% | Deaths: %deaths%

-
-
-
-
-
-
PunchCard - Last 30d
+
+

Gamemode Usage


+
+
+
+ +
+
+
+ %gm0%
-
-
- -
-
-
- %totallogins% -
-
- Login Times -
-
+
+ Survival
-
-
-
-
-
-
-
Length Distribution
+
+
+ +
+
+
+ %gm1%
-
-
- -
-
-
- %sessionaverage% -
-
- Average Length -
-
+
+ Creative
- -

If the graph contains more sessions than login times, likely cause is use of /reload (Restarts sessions).

-
-
-
-
-
-
-
-
TPS - 7d
+
+
+ +
+
+
+ %gm2%
-
-
- -
-
-
- %averagetps% -
-
- Average 7d -
-
+
+ Adventure
-
-
-
-
-
-
-
TPS - 24h
+
+
+ +
+
+
+ %gm3%
-
-
- -
-
-
- %averagetpsday% -
-
- Average 24h -
-
+
+ Spectator
-
-
-
-
-
-
-
-
Playerlist
-
-
-
- -
-
-
- %activitytotal% -
-
- Total Players -
-
-
-
- - - - - - - - - - - - - - %sortabletable% - -
Player Active Playtime Login times Registered Last seen Geolocation
-
-
-
-
-
-
-
-
-
Command usage
-
-
-
- -
-
-
- %uniquecommands% -
-
- Unique -
-
-
-
- - - - - - - - - %commanduse% - -
Command Times used
-
-
-
-
-
-
-
-
-
Geolocations
-
-
-
- -
-
-
- %activitytotal% -
-
- Total Players -
-
-
-
-
-
-
-
-
- %plugins% +
- - - - - + + + + - + - + - + - + - + - + - + - + + + \ No newline at end of file diff --git a/Plan/src/main/resources/player.html b/Plan/src/main/resources/player.html index ff4d5bf57..330fed5b0 100644 --- a/Plan/src/main/resources/player.html +++ b/Plan/src/main/resources/player.html @@ -1,12 +1,12 @@ - Plan | Inspect %name% - - - - - + +
-
- Player Analytics | Analysis -

Player Analytics v.%version%

-

%servername% | Inspect Player %name%%op%

-
+
+ Player Analytics | Analysis +

Player Analytics v.%version%

+

%servername% | Inspect Player %name%%op%

+
-
-

Last Refresh:
%refresh% ago

- - Information - - - Sessions - - - Plugins - -
-
-
-
-
-
-
-
-
Information
-
-
-
- -
-
-
- %registered% -
-
- Registered -
-
-
-
- %name% -

%active% %isonline%%banned%
- Nicknames: %nicknames%
- Playtime: %playtime%
- Login times: %logintimes%
- Times kicked: %timeskicked%
- Player kills: %playerkills% | Mob kills: %mobkills% | Deaths: %deaths%
-
- Geolocation: %geoloc%
- UUID: %uuid%
- Has Connected from ips: %ips%

-
-
-
-
-
Gamemode Usage
-
-
-
- -
-
-
- %gmtotal% -
-
- Total -
-
-
-
-
-
-
- -
-
-
- %gm0% -
-
- Survival -
-
-
-
-
- -
-
-
- %gm1% -
-
- Creative -
-
-
-
-
- -
-
-
- %gm2% -
-
- Adventure -
-
-
-
-
- -
-
-
- %gm3% -
-
- Spectator -
-
-
-
- -
-
-
-
-
-
-
Player Activity: 7d
-
-
-
- -
-
-
- %lastseen% -
-
- Last seen -
-
-
-
- -
-
-
-
-
Last 10 Kills
-
-
-
- -
-
-
- %playerkills% -
-
- Player Kills -
-
-
-
- %killstable% -
-
-
-
-
-
-
-
-
PunchCard
-
-
-
- -
-
-
- %logintimes% -
-
- Login Times -
-
-
-
- -
-
-
-
-
-
-
Length Distribution
-
-
-
- -
-
-
- %sessionaverage% -
-
- Average Length -
-
-
-
- -

If the graph contains more sessions than login times, likely cause is use of /reload (Restarts sessions).

-
-
-
-
- %plugins% -
-
-
- - - - - + + + + + + +
\ No newline at end of file diff --git a/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java b/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java index fa275a268..539038e78 100644 --- a/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java +++ b/Plan/src/test/java/main/java/com/djrapitops/plan/ui/graphs/PlayerActivityGraphCreatorTest.java @@ -1,15 +1,17 @@ package test.java.main.java.com.djrapitops.plan.ui.graphs; +import main.java.com.djrapitops.plan.data.SessionData; +import main.java.com.djrapitops.plan.ui.html.graphs.PlayerActivityGraphCreator; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; -import main.java.com.djrapitops.plan.data.SessionData; -import main.java.com.djrapitops.plan.ui.html.graphs.PlayerActivityGraphCreator; -import static org.junit.Assert.*; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * @@ -30,18 +32,6 @@ public class PlayerActivityGraphCreatorTest { public PlayerActivityGraphCreatorTest() { } - /** - * - */ - @Test - @Ignore("Useless test") - public void testGenerateDataArray() { - List sessionData = createRandomSessionDataList(); - long scale = 2592000L * 1000L; - String result = PlayerActivityGraphCreator.generateDataArray(sessionData, scale)[1]; - assertTrue("0", 0 < result.length()); - } - /** * * @return