Implemented most of Online Activity endpoint

This commit is contained in:
Rsl1122 2019-07-04 12:45:00 +03:00
parent b4907631bb
commit 4a14f2024f
12 changed files with 403 additions and 91 deletions

View File

@ -49,6 +49,14 @@ public class PlayersOnlineResolver extends TreeMap<Long, Integer> {
return Optional.of(entry.getValue());
}
public int findLonelyJoins(List<Long> joinDates) {
int lonely = 0;
for (Long joinDate : joinDates) {
if (getOnlineOn(joinDate).orElse(-1) == 0) lonely++;
}
return lonely;
}
public boolean isServerOnline(long date, long timeLimit) {
Long lastEntry = floorKey(date);
return date - lastEntry < timeLimit;

View File

@ -231,4 +231,16 @@ public class SessionsMutator {
return toPlayerDeathList().size();
}
public List<Long> toSessionStarts() {
List<Long> starts = new ArrayList<>();
sessions.forEach(session -> starts.add(session.getDate()));
return starts;
}
public double toAveragePlayersOnline(PlayersOnlineResolver playersOnlineResolver) {
return sessions.stream().map(session -> playersOnlineResolver.getOnlineOn(session.getDate()))
.filter(Optional::isPresent)
.mapToDouble(Optional::get)
.average().orElse(0.0);
}
}

View File

@ -161,14 +161,18 @@ public class ServerAggregateQueries {
};
}
public static Query<Long> totalPlaytime(UUID serverUUID) {
public static Query<Long> totalPlaytime(long after, long before, UUID serverUUID) {
String sql = SELECT + "SUM(" + SessionsTable.SESSION_END + '-' + SessionsTable.SESSION_START + ") as playtime" +
FROM + SessionsTable.TABLE_NAME +
WHERE + SessionsTable.SERVER_UUID + "=?";
WHERE + SessionsTable.SERVER_UUID + "=?" +
AND + SessionsTable.SESSION_END + ">=?" +
AND + SessionsTable.SESSION_START + "<=?";
return new QueryStatement<Long>(sql) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
statement.setLong(2, after);
statement.setLong(3, before);
}
@Override

View File

@ -252,4 +252,47 @@ public class SessionQueries {
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
public static Query<List<Session>> fetchServerSessionsWithoutKillOrWorldData(long after, long before, UUID serverUUID) {
String sql = SELECT +
SessionsTable.ID + ", " +
SessionsTable.USER_UUID + ", " +
SessionsTable.SESSION_START + ", " +
SessionsTable.SESSION_END + ", " +
SessionsTable.DEATHS + ", " +
SessionsTable.MOB_KILLS + ", " +
SessionsTable.AFK_TIME +
FROM + SessionsTable.TABLE_NAME +
WHERE + SessionsTable.SERVER_UUID + "=?" +
AND + SessionsTable.SESSION_START + ">=?" +
AND + SessionsTable.SESSION_START + "<=?";
return new QueryStatement<List<Session>>(sql, 1000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
statement.setLong(2, after);
statement.setLong(3, before);
}
@Override
public List<Session> processResults(ResultSet set) throws SQLException {
List<Session> sessions = new ArrayList<>();
while (set.next()) {
UUID uuid = UUID.fromString(set.getString(SessionsTable.USER_UUID));
long start = set.getLong(SessionsTable.SESSION_START);
long end = set.getLong(SessionsTable.SESSION_END);
int deaths = set.getInt(SessionsTable.DEATHS);
int mobKills = set.getInt(SessionsTable.MOB_KILLS);
int id = set.getInt(SessionsTable.ID);
long timeAFK = set.getLong(SessionsTable.AFK_TIME);
sessions.add(new Session(id, uuid, serverUUID, start, end, mobKills, deaths, timeAFK));
}
return sessions;
}
};
}
}

View File

@ -182,4 +182,35 @@ public class UserInfoQueries {
}
};
}
public static Query<Map<UUID, Long>> fetchRegisterDates(long after, long before, UUID serverUUID) {
String sql = SELECT +
UserInfoTable.USER_UUID + ',' +
UserInfoTable.REGISTERED +
FROM + UserInfoTable.TABLE_NAME +
WHERE + UserInfoTable.SERVER_UUID + "=?" +
AND + UserInfoTable.REGISTERED + ">=?" +
AND + UserInfoTable.REGISTERED + "<=?";
return new QueryStatement<Map<UUID, Long>>(sql, 1000) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
statement.setLong(2, after);
statement.setLong(3, before);
}
@Override
public Map<UUID, Long> processResults(ResultSet set) throws SQLException {
Map<UUID, Long> registerDates = new HashMap<>();
while (set.next()) {
registerDates.put(
UUID.fromString(set.getString(UserInfoTable.USER_UUID)),
set.getLong(UserInfoTable.REGISTERED)
);
}
return registerDates;
}
};
}
}

View File

@ -0,0 +1,218 @@
package com.djrapitops.plan.system.json;
import com.djrapitops.plan.data.container.TPS;
import com.djrapitops.plan.data.store.keys.SessionKeys;
import com.djrapitops.plan.data.store.mutators.PlayersOnlineResolver;
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
import com.djrapitops.plan.data.store.mutators.TPSMutator;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.ServerAggregateQueries;
import com.djrapitops.plan.db.access.queries.analysis.PlayerCountQueries;
import com.djrapitops.plan.db.access.queries.objects.SessionQueries;
import com.djrapitops.plan.db.access.queries.objects.TPSQueries;
import com.djrapitops.plan.db.access.queries.objects.UserInfoQueries;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.settings.config.PlanConfig;
import com.djrapitops.plan.system.settings.paths.DisplaySettings;
import com.djrapitops.plan.utilities.formatting.Formatter;
import com.djrapitops.plan.utilities.formatting.Formatters;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* Parses JSON payload for /server-page Online Activity Overview tab.
*
* @author Rsl1122
*/
@Singleton
public class OnlineActivityOverviewJSONParser {
private PlanConfig config;
private DBSystem dbSystem;
private Formatter<Long> timeAmountFormatter;
private Formatter<Double> decimalFormatter;
private Formatter<Double> percentageFormatter;
@Inject
public OnlineActivityOverviewJSONParser(
PlanConfig config,
DBSystem dbSystem,
Formatters formatters
) {
this.config = config;
this.dbSystem = dbSystem;
timeAmountFormatter = formatters.timeAmount();
decimalFormatter = formatters.decimals();
percentageFormatter = formatters.percentage();
}
public Map<String, Object> createJSONAsMap(UUID serverUUID) {
Map<String, Object> serverOverview = new HashMap<>();
serverOverview.put("numbers", createNumbersMap(serverUUID));
serverOverview.put("insights", createInsightsMap(serverUUID));
return serverOverview;
}
private Map<String, Object> createNumbersMap(UUID serverUUID) {
Database db = dbSystem.getDatabase();
long now = System.currentTimeMillis();
long dayAgo = now - TimeUnit.DAYS.toMillis(1L);
long weekAgo = now - TimeUnit.DAYS.toMillis(7L);
long halfMonthAgo = now - TimeUnit.DAYS.toMillis(15L);
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
Map<String, Object> numbers = new HashMap<>();
numbers.put("unique_players_30d", db.query(PlayerCountQueries.uniquePlayerCount(monthAgo, now, serverUUID)));
numbers.put("unique_players_30d_trend", new Trend(
db.query(PlayerCountQueries.uniquePlayerCount(monthAgo, halfMonthAgo, serverUUID)),
db.query(PlayerCountQueries.uniquePlayerCount(halfMonthAgo, now, serverUUID)),
false
));
numbers.put("unique_players_7d", db.query(PlayerCountQueries.uniquePlayerCount(weekAgo, now, serverUUID)));
numbers.put("unique_players_24h", db.query(PlayerCountQueries.uniquePlayerCount(dayAgo, now, serverUUID)));
// TODO
numbers.put("unique_players_30d_avg", -1);
numbers.put("unique_players_30d_avg_trend", new Trend(
-1,
-1,
false
));
numbers.put("unique_players_7d_avg", -1);
numbers.put("unique_players_24h_avg", -1);
numbers.put("new_players_30d", db.query(PlayerCountQueries.newPlayerCount(monthAgo, now, serverUUID)));
numbers.put("new_players_30d_trend", new Trend(
db.query(PlayerCountQueries.newPlayerCount(monthAgo, halfMonthAgo, serverUUID)),
db.query(PlayerCountQueries.newPlayerCount(halfMonthAgo, now, serverUUID)),
false
));
numbers.put("new_players_7d", db.query(PlayerCountQueries.newPlayerCount(weekAgo, now, serverUUID)));
numbers.put("new_players_24h", db.query(PlayerCountQueries.newPlayerCount(dayAgo, now, serverUUID)));
// TODO
numbers.put("new_players_30d_avg", -1);
numbers.put("new_players_30d_avg_trend", new Trend(
-1,
-1,
false
));
numbers.put("new_players_7d_avg", -1);
numbers.put("new_players_24h_avg", -1);
numbers.put("new_players_retention_30d", 0); // TODO
numbers.put("new_players_retention_30d_perc", percentageFormatter.apply(-1.0)); // TODO
numbers.put("new_players_retention_7d", 0); // TODO
numbers.put("new_players_retention_7d_perc", percentageFormatter.apply(-1.0)); // TODO
numbers.put("new_players_retention_24h", 0); // TODO
numbers.put("new_players_retention_24h_perc", percentageFormatter.apply(-1.0)); // TODO
Long playtimeMonth = db.query(ServerAggregateQueries.totalPlaytime(monthAgo, now, serverUUID));
Long playtimeWeek = db.query(ServerAggregateQueries.totalPlaytime(weekAgo, now, serverUUID));
Long playtimeDay = db.query(ServerAggregateQueries.totalPlaytime(dayAgo, now, serverUUID));
Long playtimeBefore = db.query(ServerAggregateQueries.totalPlaytime(monthAgo, halfMonthAgo, serverUUID));
Long playtimeAfter = db.query(ServerAggregateQueries.totalPlaytime(halfMonthAgo, now, serverUUID));
numbers.put("playtime_30d", timeAmountFormatter.apply(playtimeMonth));
numbers.put("playtime_30d_trend", new Trend(playtimeBefore, playtimeAfter, false, timeAmountFormatter));
numbers.put("playtime_7d", timeAmountFormatter.apply(playtimeWeek));
numbers.put("playtime_24h", timeAmountFormatter.apply(playtimeDay));
// TODO
numbers.put("playtime_30d_avg", timeAmountFormatter.apply(-1L));
numbers.put("playtime_30d_avg_trend", new Trend(
-1,
-1,
false,
timeAmountFormatter
));
numbers.put("playtime_7d_avg", timeAmountFormatter.apply(-1L));
numbers.put("playtime_24h_avg", timeAmountFormatter.apply(-1L));
Long sessionsMonth = db.query(ServerAggregateQueries.sessionCount(monthAgo, now, serverUUID));
Long sessionsWeek = db.query(ServerAggregateQueries.sessionCount(weekAgo, now, serverUUID));
Long sessionsDay = db.query(ServerAggregateQueries.sessionCount(dayAgo, now, serverUUID));
Long sessionsBefore = db.query(ServerAggregateQueries.sessionCount(monthAgo, halfMonthAgo, serverUUID));
Long sessionsAfter = db.query(ServerAggregateQueries.sessionCount(halfMonthAgo, now, serverUUID));
numbers.put("sessions_30d", sessionsMonth);
numbers.put("sessions_30d_trend", new Trend(sessionsBefore, sessionsAfter, false));
numbers.put("sessions_7d", sessionsWeek);
numbers.put("sessions_24h", sessionsDay);
Long sessionLengthAvgMonth = sessionsMonth != 0 ? playtimeMonth / sessionsMonth : 0;
Long sessionLengthAvgWeek = sessionsWeek != 0 ? playtimeWeek / sessionsWeek : 0;
Long sessionLengthAvgDay = sessionsDay != 0 ? playtimeDay / sessionsDay : 0;
numbers.put("session_length_30d_avg", timeAmountFormatter.apply(sessionLengthAvgMonth));
numbers.put("session_length_30d_trend", new Trend(
sessionsBefore != 0 ? playtimeBefore / sessionsBefore : 0,
sessionsAfter != 0 ? playtimeAfter / sessionsAfter : 0,
false,
timeAmountFormatter
));
numbers.put("session_length_7d_avg", timeAmountFormatter.apply(sessionLengthAvgWeek));
numbers.put("session_length_24h_avg", timeAmountFormatter.apply(sessionLengthAvgDay));
TPSMutator tpsMutator = new TPSMutator(db.query(TPSQueries.fetchTPSDataOfServer(monthAgo, now, serverUUID)));
numbers.put("average_tps", decimalFormatter.apply(tpsMutator.averageTPS()));
numbers.put("low_tps_spikes", tpsMutator.lowTpsSpikeCount(config.getNumber(DisplaySettings.GRAPH_TPS_THRESHOLD_MED)));
numbers.put("downtime", timeAmountFormatter.apply(tpsMutator.serverDownTime()));
return numbers;
}
private Map<String, Object> createInsightsMap(UUID serverUUID) {
Database db = dbSystem.getDatabase();
long now = System.currentTimeMillis();
long halfMonthAgo = now - TimeUnit.DAYS.toMillis(30L);
long monthAgo = now - TimeUnit.DAYS.toMillis(30L);
Map<String, Object> insights = new HashMap<>();
SessionsMutator sessions = new SessionsMutator(db.query(SessionQueries.fetchServerSessionsWithoutKillOrWorldData(monthAgo, now, serverUUID)));
List<TPS> tpsData = db.query(TPSQueries.fetchTPSDataOfServer(monthAgo, now, serverUUID));
Map<UUID, Long> registerDates = db.query(UserInfoQueries.fetchRegisterDates(monthAgo, now, serverUUID));
PlayersOnlineResolver playersOnlineResolver = new PlayersOnlineResolver(new TPSMutator(tpsData));
SessionsMutator firstSessions = sessions.filterBy(session -> {
long registered = registerDates.getOrDefault(session.getValue(SessionKeys.UUID).orElse(null), -501L);
long start = session.getDate();
return Math.abs(registered - start) < 500L;
});
SessionsMutator firstSessionsBefore = firstSessions.filterSessionsBetween(monthAgo, halfMonthAgo);
SessionsMutator firstSessionsAfter = firstSessions.filterSessionsBetween(halfMonthAgo, now);
long avgSessionLength = firstSessions.toAverageSessionLength();
long avgSessionLengthBefore = firstSessionsBefore.toAverageSessionLength();
long avgSessionLengthAfter = firstSessionsAfter.toAverageSessionLength();
insights.put("first_session_length_avg", timeAmountFormatter.apply(avgSessionLength));
insights.put("first_session_length_trend", new Trend(avgSessionLengthBefore, avgSessionLengthAfter, false, timeAmountFormatter));
int lonelyJoins = playersOnlineResolver.findLonelyJoins(sessions.toSessionStarts());
int loneJoinsBefore = playersOnlineResolver.findLonelyJoins(sessions.filterSessionsBetween(monthAgo, halfMonthAgo).toSessionStarts());
int loneJoinsAfter = playersOnlineResolver.findLonelyJoins(sessions.filterSessionsBetween(halfMonthAgo, now).toSessionStarts());
insights.put("lone_joins", lonelyJoins);
insights.put("lone_joins_trend", new Trend(loneJoinsBefore, loneJoinsAfter, true));
int newLonelyJoins = playersOnlineResolver.findLonelyJoins(firstSessions.toSessionStarts());
int newLoneJoinsBefore = playersOnlineResolver.findLonelyJoins(firstSessionsBefore.toSessionStarts());
int newLoneJoinsAfter = playersOnlineResolver.findLonelyJoins(firstSessionsAfter.toSessionStarts());
insights.put("lone_new_joins", newLonelyJoins);
insights.put("lone_new_joins_trend", new Trend(newLoneJoinsBefore, newLoneJoinsAfter, true));
double playersOnlineOnRegister = firstSessions.toAveragePlayersOnline(playersOnlineResolver);
double playersOnlineOnRegisterBefore = firstSessionsBefore.toAveragePlayersOnline(playersOnlineResolver);
double playersOnlineOnRegisterAfter = firstSessionsAfter.toAveragePlayersOnline(playersOnlineResolver);
insights.put("players_first_join_avg", decimalFormatter.apply(playersOnlineOnRegister));
insights.put("players_first_join_trend", new Trend(playersOnlineOnRegisterBefore, playersOnlineOnRegisterAfter, false, decimalFormatter));
return insights;
}
}

View File

@ -57,7 +57,7 @@ public class ServerOverviewJSONParser {
percentageFormatter = formatters.percentage();
}
public Map<String, Object> createServerOverviewJSONAsMap(UUID serverUUID) {
public Map<String, Object> createJSONAsMap(UUID serverUUID) {
Map<String, Object> serverOverview = new HashMap<>();
serverOverview.put("last_7_days", createLast7DaysMap(serverUUID));
serverOverview.put("numbers", createNumbersMap(serverUUID));
@ -101,7 +101,7 @@ public class ServerOverviewJSONParser {
numbers.put("last_peak_players", lastPeak.map(dateObj -> dateObj.getValue().toString()).orElse("-"));
numbers.put("best_peak_date", allTimePeak.map(dateFormatter).orElse("-"));
numbers.put("best_peak_players", allTimePeak.map(dateObj -> dateObj.getValue().toString()).orElse("-"));
numbers.put("playtime", timeAmountFormatter.apply(db.query(ServerAggregateQueries.totalPlaytime(serverUUID))));
numbers.put("playtime", timeAmountFormatter.apply(db.query(ServerAggregateQueries.totalPlaytime(0L, now, serverUUID))));
numbers.put("player_playtime", "-"); // TODO
numbers.put("sessions", db.query(ServerAggregateQueries.sessionCount(0L, now, serverUUID)));
numbers.put("player_kills", db.query(ServerAggregateQueries.playerKillCount(0L, now, serverUUID)));

View File

@ -0,0 +1,62 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.webserver.pages.json;
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.database.DBSystem;
import com.djrapitops.plan.system.json.OnlineActivityOverviewJSONParser;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.RequestTarget;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.data.JSONResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.UUID;
/**
* JSON handler for Online Activity Overview tab JSON requests.
*
* @author Rsl1122
*/
@Singleton
public class OnlineActivityOverviewJSONHandler extends ServerParameterJSONHandler {
private final OnlineActivityOverviewJSONParser jsonParser;
@Inject
public OnlineActivityOverviewJSONHandler(
DBSystem dbSystem,
OnlineActivityOverviewJSONParser jsonParser
) {
super(dbSystem);
this.jsonParser = jsonParser;
}
@Override
public Response getResponse(Request request, RequestTarget target) throws WebException {
UUID serverUUID = getServerUUID(target); // Can throw BadRequestException
return new JSONResponse<>(jsonParser.createJSONAsMap(serverUUID));
}
@Override
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
return auth.getWebUser().getPermLevel() <= 0;
}
}

View File

@ -38,13 +38,15 @@ public class RootJSONHandler extends TreePageHandler {
ResponseFactory responseFactory,
GraphsJSONHandler graphsJSONHandler,
PlayersTableJSONHandler playersTableJSONHandler,
ServerOverviewJSONHandler serverOverviewJSONHandler
ServerOverviewJSONHandler serverOverviewJSONHandler,
OnlineActivityOverviewJSONHandler onlineActivityOverviewJSONHandler
) {
super(responseFactory);
registerPage("players", playersTableJSONHandler);
registerPage("graph", graphsJSONHandler);
registerPage("serverOverview", serverOverviewJSONHandler);
registerPage("onlineOverview", onlineActivityOverviewJSONHandler);
}
@Override

View File

@ -31,29 +31,28 @@ import javax.inject.Singleton;
import java.util.UUID;
/**
* JSON handler for different Player table JSON requests.
* JSON handler for Server Overview tab JSON requests.
*
* @author Rsl1122
* @see com.djrapitops.plan.system.json.PlayersTableJSONParser For JSON parsing of /server players table.
*/
@Singleton
public class ServerOverviewJSONHandler extends ServerParameterJSONHandler {
private final ServerOverviewJSONParser serverOverviewJSON;
private final ServerOverviewJSONParser jsonParser;
@Inject
public ServerOverviewJSONHandler(
DBSystem dbSystem,
ServerOverviewJSONParser serverOverviewJSON
ServerOverviewJSONParser jsonParser
) {
super(dbSystem);
this.serverOverviewJSON = serverOverviewJSON;
this.jsonParser = jsonParser;
}
@Override
public Response getResponse(Request request, RequestTarget target) throws WebException {
UUID serverUUID = getServerUUID(target); // Can throw BadRequestException
return new JSONResponse<>(serverOverviewJSON.createServerOverviewJSONAsMap(serverUUID));
return new JSONResponse<>(jsonParser.createJSONAsMap(serverUUID));
}
@Override

View File

@ -1529,86 +1529,7 @@
<script>
setLoadingText('Calculating values..');
jsonRequest("../v1/serverOverview?serverName=${serverName}", loadServerOverviewValues);
loadOnlineActivityOverviewValues(
{
numbers: {
unique_players_30d: 341,
unique_players_30d_trend: {
direction: '+'
},
unique_players_7d: 233,
unique_players_24h: 34,
unique_players_30d_avg: 34,
unique_players_30d_avg_trend: {
direction: '-'
},
unique_players_7d_avg: 20,
unique_players_24h_avg: 35,
new_players_30d: 123,
new_players_30d_trend: {
direction: '+'
},
new_players_7d: 44,
new_players_24h: 23,
new_players_30d_avg: 4,
new_players_30d_avg_trend: {
direction: '+'
},
new_players_7d_avg: 6,
new_players_24h_avg: 4,
new_players_retention_30d: 63,
new_players_retention_30d_perc: '50.4%',
new_players_retention_7d: 32,
new_players_retention_7d_perc: '78.2%',
new_players_retention_24h: 4,
new_players_retention_24h_perc: '5%',
playtime_30d: '8h 5m 56s',
playtime_30d_trend: {
direction: '+'
},
playtime_7d: '5m 57s',
playtime_24h: '56s',
playtime_30d_avg: '43m 43s',
playtime_30d_avg_trend: {
direction: '-'
},
playtime_7d_avg: '32m 33s',
playtime_24h_avg: '43s',
session_length_30d_avg: '34m 4s',
session_length_30d_trend: {
direction: '+'
},
session_length_7d_avg: '24m 4s',
session_length_24h_avg: '50s',
sessions_30d: 534,
sessions_30d_trend: {
direction: '+'
},
sessions_7d: 342,
sessions_24h: 45
},
insights: {
players_first_join_avg: 3.5,
players_first_join_trend: {
direction: '+'
},
first_session_length_avg: '5m 43s',
first_session_length_trend: {
direction: '+'
},
lone_joins: 43,
lone_joins_trend: {
direction: '-',
reversed: true
},
lone_new_joins: 5,
lone_new_joins_trend: {
direction: '-',
reversed: true
}
}
}, null // TODO Replace with result of a XMLHTTPRequest
);
jsonRequest("../v1/onlineOverview?serverName=${serverName}", loadOnlineActivityOverviewValues);
loadSessionValues(
{
insights: {

View File

@ -26,6 +26,18 @@ Parameter|Expected value|Description
`serverName` | Name of a Plan server | Used for identifying Plan server that the data should be about
`serverUUID` | UUID of a Plan server | Used for identifying Plan server that the data should be about
### `GET /v1/onlineOverview`
Obtain data for Online Activity Overview tab.
Required parameters: `serverName` or `serverUUID`
Parameter|Expected value|Description
--|--|--
`serverName` | Name of a Plan server | Used for identifying Plan server that the data should be about
`serverUUID` | UUID of a Plan server | Used for identifying Plan server that the data should be about
### `GET /v1/players`
Obtain data for `/server` player list.