Made online activity overview update again on load

This commit is contained in:
Risto Lahtela 2021-02-06 11:34:02 +02:00 committed by Risto Lahtela
parent 6b4fb12755
commit b8ec15e381
8 changed files with 111 additions and 61 deletions

View File

@ -104,8 +104,16 @@ public class AsyncJSONResolverService {
} else { } else {
// If there is no version available, block thread until the new finishes being generated. // If there is no version available, block thread until the new finishes being generated.
try { try {
// updatedJSON is not null in this case ever because previousUpdates.getOrDefault(..., 0L) gets 0. // Can be null if the last update was recent and the file is deleted before next update
//noinspection ConstantConditions if (updatedJSON == null) {
updatedJSON = processing.submitNonCritical(() -> {
JSONStorage.StoredJSON created = jsonStorage.storeJson(identifier, creator.apply(serverUUID));
currentlyProcessing.remove(identifier);
jsonStorage.invalidateOlder(identifier, created.timestamp);
previousUpdates.put(identifier, created.timestamp);
return created;
}); // TODO Refactor this spaghetti code
}
return updatedJSON.get(); return updatedJSON.get();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
@ -157,8 +165,16 @@ public class AsyncJSONResolverService {
} else { } else {
// If there is no version available, block thread until the new finishes being generated. // If there is no version available, block thread until the new finishes being generated.
try { try {
// updatedJSON is not null in this case ever because previousUpdates.getOrDefault(..., 0L) gets 0. // Can be null if the last update was recent and the file is deleted before next update.
//noinspection ConstantConditions if (updatedJSON == null) {
updatedJSON = processing.submitNonCritical(() -> {
JSONStorage.StoredJSON created = jsonStorage.storeJson(identifier, creator.get());
currentlyProcessing.remove(identifier);
jsonStorage.invalidateOlder(identifier, created.timestamp);
previousUpdates.put(identifier, created.timestamp);
return created;
}); // TODO Refactor this spaghetti code
}
return updatedJSON.get(); return updatedJSON.get();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();

View File

@ -131,6 +131,7 @@ public enum HtmlLang implements Lang {
SIDE_PVP_PVE("PvP & PvE"), SIDE_PVP_PVE("PvP & PvE"),
SIDE_PERFORMANCE("Performance"), SIDE_PERFORMANCE("Performance"),
LABEL_RETENTION("New Player Retention"), LABEL_RETENTION("New Player Retention"),
DESCRIBE_RETENTION_PREDICTION("This value is a prediction based on previous players."),
TITLE_SERVER_AS_NUMBERS("Server as Numbers"), TITLE_SERVER_AS_NUMBERS("Server as Numbers"),
TITLE_ONLINE_ACTIVITY_AS_NUMBERS("Online Activity as Numbers"), TITLE_ONLINE_ACTIVITY_AS_NUMBERS("Online Activity as Numbers"),
COMPARING_15_DAYS("Comparing 15 days"), COMPARING_15_DAYS("Comparing 15 days"),

View File

@ -27,6 +27,7 @@ import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.logging.console.PluginLogger;
import com.djrapitops.plugin.logging.debug.DebugLogger; import com.djrapitops.plugin.logging.debug.DebugLogger;
import com.djrapitops.plugin.task.RunnableFactory; import com.djrapitops.plugin.task.RunnableFactory;
import org.apache.commons.lang3.StringUtils;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -81,13 +82,33 @@ public class JSONFileStorage implements JSONStorage {
@Override @Override
public StoredJSON storeJson(String identifier, String json, long timestamp) { public StoredJSON storeJson(String identifier, String json, long timestamp) {
Path writingTo = jsonDirectory.resolve(identifier + '-' + timestamp + JSON_FILE_EXTENSION); Path writingTo = jsonDirectory.resolve(identifier + '-' + timestamp + JSON_FILE_EXTENSION);
String jsonToWrite = addMissingTimestamp(json, timestamp);
try { try {
Files.createDirectories(jsonDirectory); Files.createDirectories(jsonDirectory);
Files.write(writingTo, json.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); Files.write(writingTo, jsonToWrite.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
} catch (IOException e) { } catch (IOException e) {
logger.warn("Could not write a file to " + writingTo.toFile().getAbsolutePath() + ": " + e.getMessage()); logger.warn("Could not write a file to " + writingTo.toFile().getAbsolutePath() + ": " + e.getMessage());
} }
return new StoredJSON(json, timestamp, dateFormatter); return new StoredJSON(jsonToWrite, timestamp);
}
private String addMissingTimestamp(String json, long timestamp) {
String writtenJSON;
if (!json.startsWith("{\"") || json.contains("timestamp")) {
if (!json.contains("timestamp_f")) {
writtenJSON = StringUtils.replaceOnce(json,
"\"timestamp\"",
"\"timestamp_f\":\"" + dateFormatter.apply(timestamp) + "\",\"timestamp\""
);
} else {
writtenJSON = json;
}
} else {
writtenJSON = "{\"timestamp\": " + timestamp +
",\"timestamp_f\":\"" + dateFormatter.apply(timestamp) +
"\",\"" + json.substring(2);
}
return writtenJSON;
} }
@Override @Override
@ -110,7 +131,7 @@ public class JSONFileStorage implements JSONStorage {
long timestamp = Long.parseLong(timestampMatch.group(1)); long timestamp = Long.parseLong(timestampMatch.group(1));
StringBuilder json = new StringBuilder(); StringBuilder json = new StringBuilder();
lines.forEach(json::append); lines.forEach(json::append);
return new StoredJSON(json.toString(), timestamp, dateFormatter); return new StoredJSON(json.toString(), timestamp);
} catch (IOException e) { } catch (IOException e) {
logger.warn(jsonDirectory.toFile().getAbsolutePath() + " file '" + from.getName() + "' could not be read: " + e.getMessage()); logger.warn(jsonDirectory.toFile().getAbsolutePath() + " file '" + from.getName() + "' could not be read: " + e.getMessage());
} catch (NumberFormatException e) { } catch (NumberFormatException e) {

View File

@ -17,7 +17,6 @@
package com.djrapitops.plan.storage.json; package com.djrapitops.plan.storage.json;
import com.djrapitops.plan.SubSystem; import com.djrapitops.plan.SubSystem;
import com.djrapitops.plan.delivery.formatting.Formatter;
import com.google.gson.Gson; import com.google.gson.Gson;
import java.util.Objects; import java.util.Objects;
@ -66,14 +65,8 @@ public interface JSONStorage extends SubSystem {
public final String json; public final String json;
public final long timestamp; public final long timestamp;
public StoredJSON(String json, long timestamp, Formatter<Long> dateFormatter) { public StoredJSON(String json, long timestamp) {
if (!json.startsWith("{\"") || json.contains("timestamp")) { this.json = json;
this.json = json;
} else {
this.json = "{\"timestamp\": " + timestamp +
",\"timestamp_f\":\"" + dateFormatter.apply(timestamp) +
"\",\"" + json.substring(2);
}
this.timestamp = timestamp; this.timestamp = timestamp;
} }

View File

@ -1257,4 +1257,8 @@ body.sidebar-hidden .navbar-nav {
.refresh-element { .refresh-element {
font-size: 1rem; font-size: 1rem;
margin-left: 1rem; margin-left: 1rem;
}
.refresh-element > i {
cursor: pointer;
} }

View File

@ -123,62 +123,62 @@ function loadserverOverviewValues(json, error) {
/* This function loads Online Activity Overview tab */ /* This function loads Online Activity Overview tab */
function loadOnlineActivityOverviewValues(json, error) { function loadOnlineActivityOverviewValues(json, error) {
tab = $('#online-activity-overview'); const tab = document.getElementById('online-activity-overview');
if (error) { if (error) {
displayError(tab, error); displayError($('#online-activity-overview'), error);
return; return;
} }
// Online Activity as Numbers // Online Activity as Numbers
data = json.numbers; let data = json.numbers;
element = $(tab).find('#data_numbers'); let element = tab.querySelector('#data_numbers');
$(element).find('#data_unique_players_30d').replaceWith('<td>' + data.unique_players_30d + smallTrend(data.unique_players_30d_trend) + '</td>'); element.querySelector('#data_unique_players_30d').innerHTML = data.unique_players_30d + smallTrend(data.unique_players_30d_trend);
$(element).find('#data_unique_players_7d').text(data.unique_players_7d); element.querySelector('#data_unique_players_7d').innerText = data.unique_players_7d;
$(element).find('#data_unique_players_24h').text(data.unique_players_24h); element.querySelector('#data_unique_players_24h').innerText = data.unique_players_24h;
$(element).find('#data_unique_players_30d_avg').replaceWith('<td>' + data.unique_players_30d_avg + smallTrend(data.unique_players_30d_avg_trend) + '</td>'); element.querySelector('#data_unique_players_30d_avg').innerHTML = data.unique_players_30d_avg + smallTrend(data.unique_players_30d_avg_trend);
$(element).find('#data_unique_players_7d_avg').text(data.unique_players_7d_avg); element.querySelector('#data_unique_players_7d_avg').innerText = data.unique_players_7d_avg;
$(element).find('#data_unique_players_24h_avg').text(data.unique_players_24h_avg); element.querySelector('#data_unique_players_24h_avg').innerText = data.unique_players_24h_avg;
$(element).find('#data_new_players_30d').replaceWith('<td>' + data.new_players_30d + smallTrend(data.new_players_30d_trend) + '</td>'); element.querySelector('#data_new_players_30d').innerHTML = data.new_players_30d + smallTrend(data.new_players_30d_trend);
$(element).find('#data_new_players_7d').text(data.new_players_7d); element.querySelector('#data_new_players_7d').innerText = data.new_players_7d;
$(element).find('#data_new_players_24h').text(data.new_players_24h); element.querySelector('#data_new_players_24h').innerText = data.new_players_24h;
$(element).find('#data_new_players_30d_avg').replaceWith('<td>' + data.new_players_30d_avg + smallTrend(data.new_players_30d_avg_trend) + '</td>'); element.querySelector('#data_new_players_30d_avg').innerHTML = data.new_players_30d_avg + smallTrend(data.new_players_30d_avg_trend);
$(element).find('#data_new_players_7d_avg').text(data.new_players_7d_avg); element.querySelector('#data_new_players_7d_avg').innerText = data.new_players_7d_avg;
$(element).find('#data_new_players_24h_avg').text(data.new_players_24h_avg); element.querySelector('#data_new_players_24h_avg').innerText = data.new_players_24h_avg;
$(element).find('#data_new_players_retention_30d').text('(' + data.new_players_retention_30d + '/' + data.new_players_30d + ') ' + data.new_players_retention_30d_perc); element.querySelector('#data_new_players_retention_30d').innerText = '(' + data.new_players_retention_30d + '/' + data.new_players_30d + ') ' + data.new_players_retention_30d_perc;
$(element).find('#data_new_players_retention_7d').text('(' + data.new_players_retention_7d + '/' + data.new_players_7d + ') ' + data.new_players_retention_7d_perc); element.querySelector('#data_new_players_retention_7d').innerText = '(' + data.new_players_retention_7d + '/' + data.new_players_7d + ') ' + data.new_players_retention_7d_perc;
$(element).find('#data_new_players_retention_24h').replaceWith(`<td title="This value is a prediction based on previous players.">(` + data.new_players_retention_24h + '/' + data.new_players_24h + ') ' + data.new_players_retention_24h_perc + ' <i class="far fa-fw fa-eye"></i></td>'); element.querySelector('#data_new_players_retention_24h').innerHTML = '(' + data.new_players_retention_24h + '/' + data.new_players_24h + ') ' + data.new_players_retention_24h_perc + ' <i class="far fa-fw fa-eye"></i>';
$(element).find('#data_playtime_30d').replaceWith('<td>' + data.playtime_30d + smallTrend(data.playtime_30d_trend) + '</td>'); element.querySelector('#data_playtime_30d').innerHTML = data.playtime_30d + smallTrend(data.playtime_30d_trend);
$(element).find('#data_playtime_7d').text(data.playtime_7d); element.querySelector('#data_playtime_7d').innerText = data.playtime_7d;
$(element).find('#data_playtime_24h').text(data.playtime_24h); element.querySelector('#data_playtime_24h').innerText = data.playtime_24h;
$(element).find('#data_playtime_30d_avg').replaceWith('<td>' + data.playtime_30d_avg + smallTrend(data.playtime_30d_avg_trend) + '</td>'); element.querySelector('#data_playtime_30d_avg').innerHTML = data.playtime_30d_avg + smallTrend(data.playtime_30d_avg_trend);
$(element).find('#data_playtime_7d_avg').text(data.playtime_7d_avg); element.querySelector('#data_playtime_7d_avg').innerText = data.playtime_7d_avg;
$(element).find('#data_playtime_24h_avg').text(data.playtime_24h_avg); element.querySelector('#data_playtime_24h_avg').innerText = data.playtime_24h_avg;
$(element).find('#data_session_length_30d_avg').replaceWith('<td>' + data.session_length_30d_avg + smallTrend(data.session_length_30d_trend) + '</td>'); element.querySelector('#data_session_length_30d_avg').innerHTML = data.session_length_30d_avg + smallTrend(data.session_length_30d_trend);
$(element).find('#data_session_length_7d_avg').text(data.session_length_7d_avg); element.querySelector('#data_session_length_7d_avg').innerText = data.session_length_7d_avg;
$(element).find('#data_session_length_24h_avg').text(data.session_length_24h_avg); element.querySelector('#data_session_length_24h_avg').innerText = data.session_length_24h_avg;
$(element).find('#data_sessions_30d').replaceWith('<td>' + data.sessions_30d + smallTrend(data.sessions_30d_trend) + '</td>'); element.querySelector('#data_sessions_30d').innerHTML = data.sessions_30d + smallTrend(data.sessions_30d_trend);
$(element).find('#data_sessions_7d').text(data.sessions_7d); element.querySelector('#data_sessions_7d').innerText = data.sessions_7d;
$(element).find('#data_sessions_24h').text(data.sessions_24h); element.querySelector('#data_sessions_24h').innerText = data.sessions_24h;
// Insights // Insights
data = json.insights; data = json.insights;
element = $(tab).find('#data_insights'); element = tab.querySelector('#data_insights');
$(element).find('#data_players_first_join_avg').replaceWith(data.players_first_join_avg + smallTrend(data.players_first_join_trend)); element.querySelector('#data_players_first_join_avg').innerHTML = data.players_first_join_avg + smallTrend(data.players_first_join_trend);
$(element).find('#data_first_session_length_avg').replaceWith(data.first_session_length_avg + smallTrend(data.first_session_length_trend)); element.querySelector('#data_first_session_length_avg').innerHTML = data.first_session_length_avg + smallTrend(data.first_session_length_trend);
$(element).find('#data_first_session_length_median').replaceWith(data.first_session_length_median + smallTrend(data.first_session_length_median_trend)); element.querySelector('#data_first_session_length_median').innerHTML = data.first_session_length_median + smallTrend(data.first_session_length_median_trend);
$(element).find('#data_lone_joins').replaceWith(data.lone_joins + smallTrend(data.lone_joins_trend)); element.querySelector('#data_lone_joins').innerHTML = data.lone_joins + smallTrend(data.lone_joins_trend);
$(element).find('#data_lone_new_joins').replaceWith(data.lone_new_joins + smallTrend(data.lone_new_joins_trend)) element.querySelector('#data_lone_new_joins').innerHTML = data.lone_new_joins + smallTrend(data.lone_new_joins_trend);
} }
/* This function loads Sessions tab */ /* This function loads Sessions tab */

View File

@ -4,26 +4,35 @@ function refreshingJsonRequest(address, callback, tabID) {
? `${address}&timestamp=${timestamp}` ? `${address}&timestamp=${timestamp}`
: `${address}?timestamp=${timestamp}` : `${address}?timestamp=${timestamp}`
const refreshElement = document.querySelector(`#${tabID} .refresh-element`);
refreshElement.querySelector('i').addEventListener('click', () => {
refreshElement.querySelector('.refresh-notice').innerHTML = '<i class="fa fa-fw fa-cog fa-spin"></i> Updating..';
refreshingJsonRequest(address, callback, tabID);
});
let timeout = 1000;
function makeTheRequest() { function makeTheRequest() {
jsonRequest(addressWithTimestamp, (json, error) => { jsonRequest(addressWithTimestamp, (json, error) => {
const refreshElement = document.querySelector(`#${tabID} .refresh-element`);
if (error) { if (error) {
if (error.status === 400 && error.error.includes('Attempt to get data from the future!')) { if (error.status === 400 && error.error.includes('Attempt to get data from the future!')) {
console.error(error.error); // System time not in sync with UTC console.error(error.error); // System time not in sync with UTC
refreshElement.innerHTML = "System times out of sync with UTC"; refreshElement.innerHTML = "System times out of sync with UTC";
return jsonRequest(address, callback); return jsonRequest(address, callback);
} }
refreshElement.querySelector('.refresh-notice').remove(); refreshElement.querySelector('.refresh-notice').innerHTML = "";
return callback(json, error); return callback(json, error);
} }
refreshElement.querySelector('.refresh-time').innerText = json.timestamp_f; refreshElement.querySelector('.refresh-time').innerText = json.timestamp_f;
const lastUpdated = json.timestamp; const lastUpdated = json.timestamp;
// TODO Work out the kinks with the refresh barrier time
if (lastUpdated < timestamp) { if (lastUpdated < timestamp) {
setTimeout(makeTheRequest, 5000); setTimeout(makeTheRequest, timeout);
timeout = timeout >= 12000 ? timeout : timeout * 2;
} else { } else {
refreshElement.querySelector('.refresh-notice').remove(); refreshElement.querySelector('.refresh-notice').innerHTML = "";
} }
callback(json, error); callback(json, error);
}) })

View File

@ -159,7 +159,7 @@
<h1 class="h3 mb-0 text-gray-800"><i class="sidebar-toggler fa fa-fw fa-bars"></i>${serverDisplayName} <h1 class="h3 mb-0 text-gray-800"><i class="sidebar-toggler fa fa-fw fa-bars"></i>${serverDisplayName}
&middot; Server Overview &middot; Server Overview
<span class="refresh-element"> <span class="refresh-element">
<i class="far fa-fw fa-clock"></i> <span class="refresh-time"></span> <i class="fa fa-fw fa-sync"></i> <span class="refresh-time"></span>
<span class="refresh-notice"><i class="fa fa-fw fa-cog fa-spin"></i> Updating..</span> <span class="refresh-notice"><i class="fa fa-fw fa-cog fa-spin"></i> Updating..</span>
</span> </span>
</h1> </h1>
@ -333,7 +333,12 @@
<!-- Page Heading --> <!-- Page Heading -->
<div class="d-sm-flex align-items-center justify-content-between mb-4"> <div class="d-sm-flex align-items-center justify-content-between mb-4">
<h1 class="h3 mb-0 text-gray-800"><i class="sidebar-toggler fa fa-fw fa-bars"></i>${serverDisplayName} <h1 class="h3 mb-0 text-gray-800"><i class="sidebar-toggler fa fa-fw fa-bars"></i>${serverDisplayName}
&middot; Online Activity Overview</h1> &middot; Online Activity Overview
<span class="refresh-element">
<i class="fa fa-fw fa-sync"></i> <span class="refresh-time"></span>
<span class="refresh-notice"><i class="fa fa-fw fa-cog fa-spin"></i> Updating..</span>
</span>
</h1>
${backButton} ${backButton}
</div> </div>
@ -451,7 +456,8 @@
</td> </td>
<td id="data_new_players_retention_30d"></td> <td id="data_new_players_retention_30d"></td>
<td id="data_new_players_retention_7d"></td> <td id="data_new_players_retention_7d"></td>
<td id="data_new_players_retention_24h"></td> <td id="data_new_players_retention_24h"
title="This value is a prediction based on previous players."></td>
</tr> </tr>
</tbody> </tbody>
<tbody> <tbody>
@ -1296,7 +1302,7 @@
try { try {
setLoadingText('Calculating values..'); setLoadingText('Calculating values..');
refreshingJsonRequest("../v1/serverOverview?server=${serverUUID}", loadserverOverviewValues, 'server-overview'); refreshingJsonRequest("../v1/serverOverview?server=${serverUUID}", loadserverOverviewValues, 'server-overview');
jsonRequest("../v1/onlineOverview?server=${serverUUID}", loadOnlineActivityOverviewValues); refreshingJsonRequest("../v1/onlineOverview?server=${serverUUID}", loadOnlineActivityOverviewValues, 'online-activity-overview');
jsonRequest("../v1/sessionsOverview?server=${serverUUID}", loadSessionValues); jsonRequest("../v1/sessionsOverview?server=${serverUUID}", loadSessionValues);
jsonRequest("../v1/playerVersus?server=${serverUUID}", loadPvPPvEValues); jsonRequest("../v1/playerVersus?server=${serverUUID}", loadPvPPvEValues);
jsonRequest("../v1/playerbaseOverview?server=${serverUUID}", loadPlayerbaseOverviewValues); jsonRequest("../v1/playerbaseOverview?server=${serverUUID}", loadPlayerbaseOverviewValues);