From b8ec15e381ef9a10718d2d993234eebf2ecf2aab Mon Sep 17 00:00:00 2001 From: Risto Lahtela <24460436+Rsl1122@users.noreply.github.com> Date: Sat, 6 Feb 2021 11:34:02 +0200 Subject: [PATCH] Made online activity overview update again on load --- .../json/AsyncJSONResolverService.java | 24 +++++- .../plan/settings/locale/lang/HtmlLang.java | 1 + .../plan/storage/json/JSONFileStorage.java | 27 ++++++- .../plan/storage/json/JSONStorage.java | 11 +-- .../resources/assets/plan/web/css/style.css | 4 + .../assets/plan/web/js/server-values.js | 74 +++++++++---------- .../assets/plan/web/js/xmlhttprequests.js | 17 ++++- .../resources/assets/plan/web/server.html | 14 +++- 8 files changed, 111 insertions(+), 61 deletions(-) diff --git a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/AsyncJSONResolverService.java b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/AsyncJSONResolverService.java index 207d4620b..70b494b1d 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/AsyncJSONResolverService.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/delivery/webserver/resolver/json/AsyncJSONResolverService.java @@ -104,8 +104,16 @@ public class AsyncJSONResolverService { } else { // If there is no version available, block thread until the new finishes being generated. try { - // updatedJSON is not null in this case ever because previousUpdates.getOrDefault(..., 0L) gets 0. - //noinspection ConstantConditions + // Can be null if the last update was recent and the file is deleted before next update + 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(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -157,8 +165,16 @@ public class AsyncJSONResolverService { } else { // If there is no version available, block thread until the new finishes being generated. try { - // updatedJSON is not null in this case ever because previousUpdates.getOrDefault(..., 0L) gets 0. - //noinspection ConstantConditions + // Can be null if the last update was recent and the file is deleted before next update. + 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(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/HtmlLang.java b/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/HtmlLang.java index 96c36d748..be639cd87 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/HtmlLang.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/settings/locale/lang/HtmlLang.java @@ -131,6 +131,7 @@ public enum HtmlLang implements Lang { SIDE_PVP_PVE("PvP & PvE"), SIDE_PERFORMANCE("Performance"), 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_ONLINE_ACTIVITY_AS_NUMBERS("Online Activity as Numbers"), COMPARING_15_DAYS("Comparing 15 days"), diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java index 4e0eb7802..cd3e15eeb 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONFileStorage.java @@ -27,6 +27,7 @@ import com.djrapitops.plugin.api.TimeAmount; import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.logging.debug.DebugLogger; import com.djrapitops.plugin.task.RunnableFactory; +import org.apache.commons.lang3.StringUtils; import javax.inject.Inject; import javax.inject.Singleton; @@ -81,13 +82,33 @@ public class JSONFileStorage implements JSONStorage { @Override public StoredJSON storeJson(String identifier, String json, long timestamp) { Path writingTo = jsonDirectory.resolve(identifier + '-' + timestamp + JSON_FILE_EXTENSION); + String jsonToWrite = addMissingTimestamp(json, timestamp); try { 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) { 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 @@ -110,7 +131,7 @@ public class JSONFileStorage implements JSONStorage { long timestamp = Long.parseLong(timestampMatch.group(1)); StringBuilder json = new StringBuilder(); lines.forEach(json::append); - return new StoredJSON(json.toString(), timestamp, dateFormatter); + return new StoredJSON(json.toString(), timestamp); } catch (IOException e) { logger.warn(jsonDirectory.toFile().getAbsolutePath() + " file '" + from.getName() + "' could not be read: " + e.getMessage()); } catch (NumberFormatException e) { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java index 439ed53b9..52c636132 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/storage/json/JSONStorage.java @@ -17,7 +17,6 @@ package com.djrapitops.plan.storage.json; import com.djrapitops.plan.SubSystem; -import com.djrapitops.plan.delivery.formatting.Formatter; import com.google.gson.Gson; import java.util.Objects; @@ -66,14 +65,8 @@ public interface JSONStorage extends SubSystem { public final String json; public final long timestamp; - public StoredJSON(String json, long timestamp, Formatter dateFormatter) { - if (!json.startsWith("{\"") || json.contains("timestamp")) { - this.json = json; - } else { - this.json = "{\"timestamp\": " + timestamp + - ",\"timestamp_f\":\"" + dateFormatter.apply(timestamp) + - "\",\"" + json.substring(2); - } + public StoredJSON(String json, long timestamp) { + this.json = json; this.timestamp = timestamp; } diff --git a/Plan/common/src/main/resources/assets/plan/web/css/style.css b/Plan/common/src/main/resources/assets/plan/web/css/style.css index 54cf537e9..997fd029e 100644 --- a/Plan/common/src/main/resources/assets/plan/web/css/style.css +++ b/Plan/common/src/main/resources/assets/plan/web/css/style.css @@ -1257,4 +1257,8 @@ body.sidebar-hidden .navbar-nav { .refresh-element { font-size: 1rem; margin-left: 1rem; +} + +.refresh-element > i { + cursor: pointer; } \ No newline at end of file diff --git a/Plan/common/src/main/resources/assets/plan/web/js/server-values.js b/Plan/common/src/main/resources/assets/plan/web/js/server-values.js index e152fceb3..27d709e94 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/server-values.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/server-values.js @@ -123,62 +123,62 @@ function loadserverOverviewValues(json, error) { /* This function loads Online Activity Overview tab */ function loadOnlineActivityOverviewValues(json, error) { - tab = $('#online-activity-overview'); + const tab = document.getElementById('online-activity-overview'); if (error) { - displayError(tab, error); + displayError($('#online-activity-overview'), error); return; } // Online Activity as Numbers - data = json.numbers; - element = $(tab).find('#data_numbers'); + let data = json.numbers; + let element = tab.querySelector('#data_numbers'); - $(element).find('#data_unique_players_30d').replaceWith('' + data.unique_players_30d + smallTrend(data.unique_players_30d_trend) + ''); - $(element).find('#data_unique_players_7d').text(data.unique_players_7d); - $(element).find('#data_unique_players_24h').text(data.unique_players_24h); + element.querySelector('#data_unique_players_30d').innerHTML = data.unique_players_30d + smallTrend(data.unique_players_30d_trend); + element.querySelector('#data_unique_players_7d').innerText = data.unique_players_7d; + element.querySelector('#data_unique_players_24h').innerText = data.unique_players_24h; - $(element).find('#data_unique_players_30d_avg').replaceWith('' + 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).find('#data_unique_players_24h_avg').text(data.unique_players_24h_avg); + element.querySelector('#data_unique_players_30d_avg').innerHTML = data.unique_players_30d_avg + smallTrend(data.unique_players_30d_avg_trend); + element.querySelector('#data_unique_players_7d_avg').innerText = data.unique_players_7d_avg; + element.querySelector('#data_unique_players_24h_avg').innerText = data.unique_players_24h_avg; - $(element).find('#data_new_players_30d').replaceWith('' + data.new_players_30d + smallTrend(data.new_players_30d_trend) + ''); - $(element).find('#data_new_players_7d').text(data.new_players_7d); - $(element).find('#data_new_players_24h').text(data.new_players_24h); + element.querySelector('#data_new_players_30d').innerHTML = data.new_players_30d + smallTrend(data.new_players_30d_trend); + element.querySelector('#data_new_players_7d').innerText = data.new_players_7d; + element.querySelector('#data_new_players_24h').innerText = data.new_players_24h; - $(element).find('#data_new_players_30d_avg').replaceWith('' + 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).find('#data_new_players_24h_avg').text(data.new_players_24h_avg); + element.querySelector('#data_new_players_30d_avg').innerHTML = data.new_players_30d_avg + smallTrend(data.new_players_30d_avg_trend); + element.querySelector('#data_new_players_7d_avg').innerText = data.new_players_7d_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).find('#data_new_players_retention_7d').text('(' + data.new_players_retention_7d + '/' + data.new_players_7d + ') ' + data.new_players_retention_7d_perc); - $(element).find('#data_new_players_retention_24h').replaceWith(`(` + data.new_players_retention_24h + '/' + data.new_players_24h + ') ' + data.new_players_retention_24h_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.querySelector('#data_new_players_retention_7d').innerText = '(' + data.new_players_retention_7d + '/' + data.new_players_7d + ') ' + data.new_players_retention_7d_perc; + element.querySelector('#data_new_players_retention_24h').innerHTML = '(' + data.new_players_retention_24h + '/' + data.new_players_24h + ') ' + data.new_players_retention_24h_perc + ' '; - $(element).find('#data_playtime_30d').replaceWith('' + data.playtime_30d + smallTrend(data.playtime_30d_trend) + ''); - $(element).find('#data_playtime_7d').text(data.playtime_7d); - $(element).find('#data_playtime_24h').text(data.playtime_24h); + element.querySelector('#data_playtime_30d').innerHTML = data.playtime_30d + smallTrend(data.playtime_30d_trend); + element.querySelector('#data_playtime_7d').innerText = data.playtime_7d; + element.querySelector('#data_playtime_24h').innerText = data.playtime_24h; - $(element).find('#data_playtime_30d_avg').replaceWith('' + data.playtime_30d_avg + smallTrend(data.playtime_30d_avg_trend) + ''); - $(element).find('#data_playtime_7d_avg').text(data.playtime_7d_avg); - $(element).find('#data_playtime_24h_avg').text(data.playtime_24h_avg); + element.querySelector('#data_playtime_30d_avg').innerHTML = data.playtime_30d_avg + smallTrend(data.playtime_30d_avg_trend); + element.querySelector('#data_playtime_7d_avg').innerText = data.playtime_7d_avg; + element.querySelector('#data_playtime_24h_avg').innerText = data.playtime_24h_avg; - $(element).find('#data_session_length_30d_avg').replaceWith('' + 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).find('#data_session_length_24h_avg').text(data.session_length_24h_avg); + element.querySelector('#data_session_length_30d_avg').innerHTML = data.session_length_30d_avg + smallTrend(data.session_length_30d_trend); + element.querySelector('#data_session_length_7d_avg').innerText = data.session_length_7d_avg; + element.querySelector('#data_session_length_24h_avg').innerText = data.session_length_24h_avg; - $(element).find('#data_sessions_30d').replaceWith('' + data.sessions_30d + smallTrend(data.sessions_30d_trend) + ''); - $(element).find('#data_sessions_7d').text(data.sessions_7d); - $(element).find('#data_sessions_24h').text(data.sessions_24h); + element.querySelector('#data_sessions_30d').innerHTML = data.sessions_30d + smallTrend(data.sessions_30d_trend); + element.querySelector('#data_sessions_7d').innerText = data.sessions_7d; + element.querySelector('#data_sessions_24h').innerText = data.sessions_24h; // 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).find('#data_first_session_length_avg').replaceWith(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).find('#data_lone_joins').replaceWith(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_players_first_join_avg').innerHTML = data.players_first_join_avg + smallTrend(data.players_first_join_trend); + element.querySelector('#data_first_session_length_avg').innerHTML = data.first_session_length_avg + smallTrend(data.first_session_length_trend); + element.querySelector('#data_first_session_length_median').innerHTML = data.first_session_length_median + smallTrend(data.first_session_length_median_trend); + element.querySelector('#data_lone_joins').innerHTML = data.lone_joins + smallTrend(data.lone_joins_trend); + element.querySelector('#data_lone_new_joins').innerHTML = data.lone_new_joins + smallTrend(data.lone_new_joins_trend); } /* This function loads Sessions tab */ diff --git a/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js b/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js index 3615b4bc9..4cadca183 100644 --- a/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js +++ b/Plan/common/src/main/resources/assets/plan/web/js/xmlhttprequests.js @@ -4,26 +4,35 @@ function refreshingJsonRequest(address, callback, tabID) { ? `${address}×tamp=${timestamp}` : `${address}?timestamp=${timestamp}` + const refreshElement = document.querySelector(`#${tabID} .refresh-element`); + refreshElement.querySelector('i').addEventListener('click', () => { + refreshElement.querySelector('.refresh-notice').innerHTML = ' Updating..'; + refreshingJsonRequest(address, callback, tabID); + }); + + let timeout = 1000; + function makeTheRequest() { jsonRequest(addressWithTimestamp, (json, error) => { - const refreshElement = document.querySelector(`#${tabID} .refresh-element`); if (error) { 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 refreshElement.innerHTML = "System times out of sync with UTC"; return jsonRequest(address, callback); } - refreshElement.querySelector('.refresh-notice').remove(); + refreshElement.querySelector('.refresh-notice').innerHTML = ""; return callback(json, error); } refreshElement.querySelector('.refresh-time').innerText = json.timestamp_f; const lastUpdated = json.timestamp; + // TODO Work out the kinks with the refresh barrier time if (lastUpdated < timestamp) { - setTimeout(makeTheRequest, 5000); + setTimeout(makeTheRequest, timeout); + timeout = timeout >= 12000 ? timeout : timeout * 2; } else { - refreshElement.querySelector('.refresh-notice').remove(); + refreshElement.querySelector('.refresh-notice').innerHTML = ""; } callback(json, error); }) diff --git a/Plan/common/src/main/resources/assets/plan/web/server.html b/Plan/common/src/main/resources/assets/plan/web/server.html index c8b23cf68..4620c57ae 100644 --- a/Plan/common/src/main/resources/assets/plan/web/server.html +++ b/Plan/common/src/main/resources/assets/plan/web/server.html @@ -159,7 +159,7 @@

${serverDisplayName} · Server Overview - + Updating..

@@ -333,7 +333,12 @@

${serverDisplayName} - · Online Activity Overview

+ · Online Activity Overview + + + Updating.. + + ${backButton}
@@ -451,7 +456,8 @@ - + @@ -1296,7 +1302,7 @@ try { setLoadingText('Calculating values..'); 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/playerVersus?server=${serverUUID}", loadPvPPvEValues); jsonRequest("../v1/playerbaseOverview?server=${serverUUID}", loadPlayerbaseOverviewValues);