/* * This file is part of Player Analytics (Plan). * * Plan is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License v3 as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Plan is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Plan. If not, see . */ package com.djrapitops.plan.delivery.rendering.json.graphs; import com.djrapitops.plan.delivery.domain.DateMap; import com.djrapitops.plan.delivery.domain.DateObj; import com.djrapitops.plan.delivery.domain.JoinAddressCount; import com.djrapitops.plan.delivery.domain.JoinAddressCounts; import com.djrapitops.plan.delivery.domain.datatransfer.ServerDto; import com.djrapitops.plan.delivery.domain.datatransfer.graphs.GraphCollection; import com.djrapitops.plan.delivery.domain.datatransfer.graphs.ServerSpecificLineGraph; import com.djrapitops.plan.delivery.domain.mutators.MutatorFunctions; import com.djrapitops.plan.delivery.domain.mutators.PingMutator; import com.djrapitops.plan.delivery.domain.mutators.TPSMutator; import com.djrapitops.plan.delivery.rendering.json.graphs.bar.BarGraph; import com.djrapitops.plan.delivery.rendering.json.graphs.line.LineGraph; import com.djrapitops.plan.delivery.rendering.json.graphs.line.LineGraphFactory; import com.djrapitops.plan.delivery.rendering.json.graphs.line.PingGraph; import com.djrapitops.plan.delivery.rendering.json.graphs.line.Point; import com.djrapitops.plan.delivery.rendering.json.graphs.pie.Pie; import com.djrapitops.plan.delivery.rendering.json.graphs.pie.PieSlice; import com.djrapitops.plan.delivery.rendering.json.graphs.pie.WorldPie; import com.djrapitops.plan.delivery.rendering.json.graphs.special.WorldMap; import com.djrapitops.plan.delivery.rendering.json.graphs.stack.StackGraph; import com.djrapitops.plan.gathering.domain.FinishedSession; import com.djrapitops.plan.gathering.domain.Ping; import com.djrapitops.plan.gathering.domain.WorldTimes; import com.djrapitops.plan.identification.Server; import com.djrapitops.plan.identification.ServerUUID; import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.paths.DataGatheringSettings; import com.djrapitops.plan.settings.config.paths.DisplaySettings; import com.djrapitops.plan.settings.config.paths.TimeSettings; import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.lang.GenericLang; import com.djrapitops.plan.settings.theme.Theme; import com.djrapitops.plan.settings.theme.ThemeVal; import com.djrapitops.plan.storage.database.DBSystem; import com.djrapitops.plan.storage.database.Database; import com.djrapitops.plan.storage.database.queries.analysis.ActivityIndexQueries; import com.djrapitops.plan.storage.database.queries.analysis.NetworkActivityIndexQueries; import com.djrapitops.plan.storage.database.queries.analysis.PlayerCountQueries; import com.djrapitops.plan.storage.database.queries.objects.*; import com.djrapitops.plan.storage.database.sql.tables.JoinAddressTable; import com.djrapitops.plan.utilities.comparators.DateHolderOldestComparator; import com.djrapitops.plan.utilities.comparators.PieSliceComparator; import com.djrapitops.plan.utilities.java.Lists; import com.djrapitops.plan.utilities.java.Maps; import net.playeranalytics.plugin.scheduling.TimeAmount; import javax.inject.Inject; import javax.inject.Singleton; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * Creates Graph related Data JSON. * * @author AuroraLS3 */ @Singleton public class GraphJSONCreator { private final PlanConfig config; private final Locale locale; private final Theme theme; private final DBSystem dbSystem; private final Graphs graphs; @Inject public GraphJSONCreator( PlanConfig config, Locale locale, Theme theme, DBSystem dbSystem, Graphs graphs ) { this.config = config; this.locale = locale; this.theme = theme; this.dbSystem = dbSystem; this.graphs = graphs; } public String performanceGraphJSON(ServerUUID serverUUID) { long now = System.currentTimeMillis(); Database db = dbSystem.getDatabase(); LineGraphFactory lineGraphs = graphs.line(); long halfYearAgo = now - TimeUnit.DAYS.toMillis(180); TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(halfYearAgo, now, serverUUID))); return '{' + "\"playersOnline\":" + lineGraphs.playersOnlineGraph(tpsMutator).toHighChartsSeries() + ",\"tps\":" + lineGraphs.tpsGraph(tpsMutator).toHighChartsSeries() + ",\"cpu\":" + lineGraphs.cpuGraph(tpsMutator).toHighChartsSeries() + ",\"ram\":" + lineGraphs.ramGraph(tpsMutator).toHighChartsSeries() + ",\"entities\":" + lineGraphs.entityGraph(tpsMutator).toHighChartsSeries() + ",\"chunks\":" + lineGraphs.chunkGraph(tpsMutator).toHighChartsSeries() + ",\"disk\":" + lineGraphs.diskGraph(tpsMutator).toHighChartsSeries() + ",\"colors\":{" + "\"playersOnline\":\"" + theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE) + "\"," + "\"cpu\":\"" + theme.getValue(ThemeVal.GRAPH_CPU) + "\"," + "\"ram\":\"" + theme.getValue(ThemeVal.GRAPH_RAM) + "\"," + "\"entities\":\"" + theme.getValue(ThemeVal.GRAPH_ENTITIES) + "\"," + "\"chunks\":\"" + theme.getValue(ThemeVal.GRAPH_CHUNKS) + "\"," + "\"low\":\"" + theme.getValue(ThemeVal.GRAPH_TPS_LOW) + "\"," + "\"med\":\"" + theme.getValue(ThemeVal.GRAPH_TPS_MED) + "\"," + "\"high\":\"" + theme.getValue(ThemeVal.GRAPH_TPS_HIGH) + "\"}" + ",\"zones\":{" + "\"tpsThresholdMed\":" + config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_MED) + ',' + "\"tpsThresholdHigh\":" + config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_HIGH) + ',' + "\"diskThresholdMed\":" + config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_MED) + ',' + "\"diskThresholdHigh\":" + config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_HIGH) + "}}"; } public Map optimizedPerformanceGraphJSON(ServerUUID serverUUID) { long now = System.currentTimeMillis(); long twoMonthsAgo = now - TimeUnit.DAYS.toMillis(60); long monthAgo = now - TimeUnit.DAYS.toMillis(30); long lowestResolution = TimeUnit.MINUTES.toMillis(20); long lowResolution = TimeUnit.MINUTES.toMillis(5); Database db = dbSystem.getDatabase(); TPSMutator lowestResolutionData = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServerInResolution(0, twoMonthsAgo, lowestResolution, serverUUID))); TPSMutator lowResolutionData = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServerInResolution(twoMonthsAgo, monthAgo, lowResolution, serverUUID))); TPSMutator highResolutionData = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(monthAgo, now, serverUUID))); String serverName = db.query(ServerQueries.fetchServerMatchingIdentifier(serverUUID)) .map(Server::getIdentifiableName) .orElse(serverUUID.toString()); List values = lowestResolutionData.toArrays(new LineGraph.GapStrategy( config.isTrue(DisplaySettings.GAPS_IN_GRAPH_DATA), lowestResolution + TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(30), null )); values.addAll(lowResolutionData.toArrays(new LineGraph.GapStrategy( config.isTrue(DisplaySettings.GAPS_IN_GRAPH_DATA), lowResolution + TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(30), null ))); values.addAll(highResolutionData.toArrays(new LineGraph.GapStrategy( config.isTrue(DisplaySettings.GAPS_IN_GRAPH_DATA), TimeUnit.MINUTES.toMillis(3), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(30), null ))); return Maps.builder(String.class, Object.class) .put("keys", new String[]{"date", "playersOnline", "tps", "cpu", "ram", "entities", "chunks", "disk"}) .put("values", values) .put("colors", Maps.builder(String.class, Object.class) .put("playersOnline", theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE)) .put("cpu", theme.getValue(ThemeVal.GRAPH_CPU)) .put("ram", theme.getValue(ThemeVal.GRAPH_RAM)) .put("entities", theme.getValue(ThemeVal.GRAPH_ENTITIES)) .put("chunks", theme.getValue(ThemeVal.GRAPH_CHUNKS)) .put("low", theme.getValue(ThemeVal.GRAPH_TPS_LOW)) .put("med", theme.getValue(ThemeVal.GRAPH_TPS_MED)) .put("high", theme.getValue(ThemeVal.GRAPH_TPS_HIGH)) .build()) .put("zones", Maps.builder(String.class, Object.class) .put("tpsThresholdMed", config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_MED)) .put("tpsThresholdHigh", config.get(DisplaySettings.GRAPH_TPS_THRESHOLD_HIGH)) .put("diskThresholdMed", config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_MED)) .put("diskThresholdHigh", config.get(DisplaySettings.GRAPH_DISK_THRESHOLD_HIGH)) .build()) .put("serverName", serverName) .put("serverUUID", serverUUID) .build(); } public String playersOnlineGraph(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); long now = System.currentTimeMillis(); long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L); List points = Lists.map( db.query(TPSQueries.fetchPlayersOnlineOfServer(halfYearAgo, now, serverUUID)), Point::fromDateObj ); return "{\"playersOnline\":" + graphs.line().lineGraph(points).toHighChartsSeries() + ",\"color\":\"" + theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE) + "\"}"; } public String uniqueAndNewGraphJSON(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); LineGraphFactory lineGraphs = graphs.line(); long now = System.currentTimeMillis(); long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L); int timeZoneOffset = config.getTimeZone().getOffset(now); NavigableMap uniquePerDay = db.query( PlayerCountQueries.uniquePlayerCounts(halfYearAgo, now, timeZoneOffset, serverUUID) ); NavigableMap newPerDay = db.query( PlayerCountQueries.newPlayerCounts(halfYearAgo, now, timeZoneOffset, serverUUID) ); return createUniqueAndNewJSON(lineGraphs, uniquePerDay, newPerDay, TimeUnit.DAYS.toMillis(1L)); } public String hourlyUniqueAndNewGraphJSON(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); LineGraphFactory lineGraphs = graphs.line(); long now = System.currentTimeMillis(); long weekAgo = now - TimeUnit.DAYS.toMillis(7L); int timeZoneOffset = config.getTimeZone().getOffset(now); NavigableMap uniquePerDay = db.query( PlayerCountQueries.hourlyUniquePlayerCounts(weekAgo, now, timeZoneOffset, serverUUID) ); NavigableMap newPerDay = db.query( PlayerCountQueries.newPlayerCounts(weekAgo, now, timeZoneOffset, serverUUID) ); return createUniqueAndNewJSON(lineGraphs, uniquePerDay, newPerDay, TimeUnit.HOURS.toMillis(1L)); } public String createUniqueAndNewJSON(LineGraphFactory lineGraphs, NavigableMap uniquePerDay, NavigableMap newPerDay, long gapFillPeriod) { LineGraph.GapStrategy gapStrategy = new LineGraph.GapStrategy(true, gapFillPeriod, 0, gapFillPeriod, 0.0); return "{\"uniquePlayers\":" + lineGraphs.lineGraph(MutatorFunctions.toPoints( MutatorFunctions.addMissing(uniquePerDay, gapFillPeriod, 0) ), gapStrategy).toHighChartsSeries() + ",\"newPlayers\":" + lineGraphs.lineGraph(MutatorFunctions.toPoints( MutatorFunctions.addMissing(newPerDay, gapFillPeriod, 0) ), gapStrategy).toHighChartsSeries() + ",\"colors\":{" + "\"playersOnline\":\"" + theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE) + "\"," + "\"newPlayers\":\"" + theme.getValue(ThemeVal.LIGHT_GREEN) + "\"" + "}}"; } public String uniqueAndNewGraphJSON() { Database db = dbSystem.getDatabase(); LineGraphFactory lineGraphs = graphs.line(); long now = System.currentTimeMillis(); long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L); int timeZoneOffset = config.getTimeZone().getOffset(now); NavigableMap uniquePerDay = db.query( PlayerCountQueries.uniquePlayerCounts(halfYearAgo, now, timeZoneOffset) ); NavigableMap newPerDay = db.query( PlayerCountQueries.newPlayerCounts(halfYearAgo, now, timeZoneOffset) ); return createUniqueAndNewJSON(lineGraphs, uniquePerDay, newPerDay, TimeUnit.DAYS.toMillis(1L)); } public String hourlyUniqueAndNewGraphJSON() { Database db = dbSystem.getDatabase(); LineGraphFactory lineGraphs = graphs.line(); long now = System.currentTimeMillis(); long weekAgo = now - TimeUnit.DAYS.toMillis(7L); int timeZoneOffset = config.getTimeZone().getOffset(now); NavigableMap uniquePerDay = db.query( PlayerCountQueries.hourlyUniquePlayerCounts(weekAgo, now, timeZoneOffset) ); NavigableMap newPerDay = db.query( PlayerCountQueries.hourlyNewPlayerCounts(weekAgo, now, timeZoneOffset) ); return createUniqueAndNewJSON(lineGraphs, uniquePerDay, newPerDay, TimeUnit.HOURS.toMillis(1L)); } public String serverCalendarJSON(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); long now = System.currentTimeMillis(); long twoYearsAgo = now - TimeUnit.DAYS.toMillis(730L); int timeZoneOffset = config.getTimeZone().getOffset(now); NavigableMap uniquePerDay = db.query( PlayerCountQueries.uniquePlayerCounts(twoYearsAgo, now, timeZoneOffset, serverUUID) ); NavigableMap newPerDay = db.query( PlayerCountQueries.newPlayerCounts(twoYearsAgo, now, timeZoneOffset, serverUUID) ); NavigableMap playtimePerDay = db.query( SessionQueries.playtimePerDay(twoYearsAgo, now, timeZoneOffset, serverUUID) ); NavigableMap sessionsPerDay = db.query( SessionQueries.sessionCountPerDay(twoYearsAgo, now, timeZoneOffset, serverUUID) ); return "{\"data\":" + graphs.calendar().serverCalendar( uniquePerDay, newPerDay, playtimePerDay, sessionsPerDay ).toCalendarSeries() + ",\"firstDay\":" + 1 + '}'; } public String networkCalendarJSON() { Database db = dbSystem.getDatabase(); long now = System.currentTimeMillis(); long twoYearsAgo = now - TimeUnit.DAYS.toMillis(730L); int timeZoneOffset = config.getTimeZone().getOffset(now); NavigableMap uniquePerDay = db.query( PlayerCountQueries.uniquePlayerCounts(twoYearsAgo, now, timeZoneOffset) ); NavigableMap newPerDay = db.query( PlayerCountQueries.newPlayerCounts(twoYearsAgo, now, timeZoneOffset) ); NavigableMap playtimePerDay = db.query( SessionQueries.playtimePerDay(twoYearsAgo, now, timeZoneOffset) ); NavigableMap sessionsPerDay = db.query( SessionQueries.sessionCountPerDay(twoYearsAgo, now, timeZoneOffset) ); return "{\"data\":" + graphs.calendar().serverCalendar( uniquePerDay, newPerDay, playtimePerDay, sessionsPerDay ).toCalendarSeries() + ",\"firstDay\":" + 1 + '}'; } public Map serverWorldPieJSONAsMap(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); WorldTimes worldTimes = db.query(WorldTimesQueries.fetchServerTotalWorldTimes(serverUUID)); WorldPie worldPie = graphs.pie().worldPie(worldTimes); return Maps.builder(String.class, Object.class) .put("world_series", worldPie.getSlices()) .put("gm_series", worldPie.toHighChartsDrillDownMaps()) .build(); } public Map activityGraphsJSONAsMap(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); long date = System.currentTimeMillis(); Long threshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD); DateMap> activityData = new DateMap<>(); for (long time = date; time >= date - TimeAmount.MONTH.toMillis(2L); time -= TimeAmount.WEEK.toMillis(1L)) { activityData.put(time, db.query(ActivityIndexQueries.fetchActivityIndexGroupingsOn(time, serverUUID, threshold))); } return createActivityGraphJSON(activityData); } public Map createActivityGraphJSON(DateMap> activityData) { Map.Entry> lastActivityEntry = activityData.lastEntry(); Pie activityPie = graphs.pie().activityPie(lastActivityEntry != null ? lastActivityEntry.getValue() : Collections.emptyMap()); StackGraph activityStackGraph = graphs.stack().activityStackGraph(activityData); return Maps.builder(String.class, Object.class) .put("activity_series", activityStackGraph.getDataSets()) .put("activity_labels", activityStackGraph.getLabels()) .put("activity_pie_series", activityPie.getSlices()) .build(); } public Map activityGraphsJSONAsMap() { Database db = dbSystem.getDatabase(); long date = System.currentTimeMillis(); Long threshold = config.get(TimeSettings.ACTIVE_PLAY_THRESHOLD); DateMap> activityData = new DateMap<>(); for (long time = date; time >= date - TimeAmount.MONTH.toMillis(2L); time -= TimeAmount.WEEK.toMillis(1L)) { activityData.put(time, db.query(NetworkActivityIndexQueries.fetchActivityIndexGroupingsOn(time, threshold))); } return createActivityGraphJSON(activityData); } public Map geolocationGraphsJSONAsMap(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); Map geolocationCounts = db.query(GeoInfoQueries.serverGeolocationCounts(serverUUID)); return createGeolocationJSON(geolocationCounts); } public Map createGeolocationJSON(Map geolocationCounts) { BarGraph geolocationBarGraph = graphs.bar().geolocationBarGraph(geolocationCounts); WorldMap worldMap = graphs.special().worldMap(geolocationCounts); return Maps.builder(String.class, Object.class) .put("geolocations_enabled", config.get(DataGatheringSettings.GEOLOCATIONS) && config.get(DataGatheringSettings.ACCEPT_GEOLITE2_EULA)) .put("geolocation_series", worldMap.getEntries()) .put("geolocation_bar_series", geolocationBarGraph.getBars()) .put("colors", Maps.builder(String.class, String.class) .put("low", theme.getValue(ThemeVal.WORLD_MAP_LOW)) .put("high", theme.getValue(ThemeVal.WORLD_MAP_HIGH)) .put("bars", theme.getValue(ThemeVal.GREEN)) .build()) .build(); } public Map geolocationGraphsJSONAsMap() { Database db = dbSystem.getDatabase(); Map geolocationCounts = db.query(GeoInfoQueries.networkGeolocationCounts()); return createGeolocationJSON(geolocationCounts); } public String pingGraphsJSON(ServerUUID serverUUID) { Database db = dbSystem.getDatabase(); long now = System.currentTimeMillis(); List pings = db.query(PingQueries.fetchPingDataOfServer(now - TimeUnit.DAYS.toMillis(180L), now, serverUUID)); PingGraph pingGraph = graphs.line().pingGraph(new PingMutator(pings).mutateToByMinutePings().all()); return "{\"min_ping_series\":" + pingGraph.getMinGraph().toHighChartsSeries() + ",\"avg_ping_series\":" + pingGraph.getAvgGraph().toHighChartsSeries() + ",\"max_ping_series\":" + pingGraph.getMaxGraph().toHighChartsSeries() + ",\"colors\":{" + "\"min\":\"" + theme.getValue(ThemeVal.GRAPH_MIN_PING) + "\"," + "\"avg\":\"" + theme.getValue(ThemeVal.GRAPH_AVG_PING) + "\"," + "\"max\":\"" + theme.getValue(ThemeVal.GRAPH_MAX_PING) + "\"" + "}}"; } public Map punchCardJSONAsMap(ServerUUID serverUUID) { long now = System.currentTimeMillis(); long monthAgo = now - TimeUnit.DAYS.toMillis(30L); List sessions = dbSystem.getDatabase().query( SessionQueries.fetchServerSessionsWithoutKillOrWorldData(monthAgo, now, serverUUID) ); return Maps.builder(String.class, Object.class) .put("punchCard", graphs.special().punchCard(sessions).getDots()) .put("color", theme.getValue(ThemeVal.GRAPH_PUNCHCARD)) .build(); } public Map serverPreferencePieJSONAsMap() { long now = System.currentTimeMillis(); long monthAgo = now - TimeUnit.DAYS.toMillis(30L); String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE); Map playtimePerServer = dbSystem.getDatabase().query(SessionQueries.playtimePerServer(monthAgo, now)); return Maps.builder(String.class, Object.class) .put("server_pie_colors", pieColors) .put("server_pie_series_30d", graphs.pie().serverPreferencePie(playtimePerServer).getSlices()) .build(); } public Map playerHostnamePieJSONAsMap() { String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE); Map joinAddresses = dbSystem.getDatabase().query(JoinAddressQueries.latestJoinAddresses()); translateUnknown(joinAddresses); List slices = graphs.pie().joinAddressPie(joinAddresses).getSlices(); slices.sort(new PieSliceComparator()); return Maps.builder(String.class, Object.class) .put("colors", pieColors) .put("slices", slices) .build(); } public Map playerHostnamePieJSONAsMap(ServerUUID serverUUID) { String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE); Map joinAddresses = dbSystem.getDatabase().query(JoinAddressQueries.latestJoinAddresses(serverUUID)); translateUnknown(joinAddresses); List slices = graphs.pie().joinAddressPie(joinAddresses).getSlices(); slices.sort(new PieSliceComparator()); return Maps.builder(String.class, Object.class) .put("colors", pieColors) .put("slices", slices) .build(); } public void translateUnknown(Map joinAddresses) { Integer unknown = joinAddresses.get(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP); if (unknown != null) { joinAddresses.remove(JoinAddressTable.DEFAULT_VALUE_FOR_LOOKUP); joinAddresses.put(GenericLang.UNKNOWN.getKey(), unknown); } } public Map joinAddressesByDay(ServerUUID serverUUID, long after, long before) { String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE); List>> joinAddresses = dbSystem.getDatabase().query(JoinAddressQueries.joinAddressesPerDay(serverUUID, config.getTimeZone().getOffset(System.currentTimeMillis()), after, before)); return mapToJson(pieColors, joinAddresses); } public Map joinAddressesByDay(long after, long before) { String[] pieColors = theme.getPieColors(ThemeVal.GRAPH_WORLD_PIE); List>> joinAddresses = dbSystem.getDatabase().query(JoinAddressQueries.joinAddressesPerDay(config.getTimeZone().getOffset(System.currentTimeMillis()), after, before)); return mapToJson(pieColors, joinAddresses); } private Map mapToJson(String[] pieColors, List>> joinAddresses) { for (DateObj> addressesByDate : joinAddresses) { translateUnknown(addressesByDate.getValue()); } List joinAddressCounts = joinAddresses.stream() .map(addressesOnDay -> new JoinAddressCounts( addressesOnDay.getDate(), addressesOnDay.getValue().entrySet() .stream() .map(JoinAddressCount::new) .sorted() .collect(Collectors.toList()))) .sorted(new DateHolderOldestComparator()) .collect(Collectors.toList()); return Maps.builder(String.class, Object.class) .put("colors", pieColors) .put("join_addresses_by_date", joinAddressCounts) .build(); } public GraphCollection proxyPlayersOnlineGraphs() { Database db = dbSystem.getDatabase(); long now = System.currentTimeMillis(); long halfYearAgo = now - TimeUnit.DAYS.toMillis(180L); List proxyGraphs = new ArrayList<>(); for (Server proxy : db.query(ServerQueries.fetchProxyServers())) { ServerUUID proxyUUID = proxy.getUuid(); List points = Lists.map( db.query(TPSQueries.fetchPlayersOnlineOfServer(halfYearAgo, now, proxyUUID)), point -> Point.fromDateObj(point).toArray() ); proxyGraphs.add(new ServerSpecificLineGraph(points, ServerDto.fromServer(proxy))); } return new GraphCollection<>(proxyGraphs, theme.getValue(ThemeVal.GRAPH_PLAYERS_ONLINE)); } }