diff --git a/assets/js/app.js b/assets/js/app.js index a3b3ab6..8458157 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -102,7 +102,7 @@ export class App { .reduce((sum, current) => sum + current, 0) } - addServer = (pings) => { + addServer = (pings, timestampPoints) => { // Even if the backend has never pinged the server, the frontend is promised a placeholder object. // result = undefined // error = defined with "Waiting" description @@ -114,14 +114,14 @@ export class App { // Push the historical data into the graph // This will trim and format the data so it is ready for the graph to render once init - serverRegistration.addGraphPoints(pings) + serverRegistration.addGraphPoints(pings, timestampPoints) // Create the plot instance internally with the restructured and cleaned data serverRegistration.buildPlotInstance() // Handle the last known state (if any) as an incoming update // This triggers the main update pipeline and enables centralized update handling - serverRegistration.updateServerStatus(latestPing, latestPing.timestamp, true, this.publicConfig.minecraftVersions) + serverRegistration.updateServerStatus(latestPing, true, this.publicConfig.minecraftVersions) // Allow the ServerRegistration to bind any DOM events with app instance context serverRegistration.initEventListeners() diff --git a/assets/js/servers.js b/assets/js/servers.js index f0717da..40cc517 100644 --- a/assets/js/servers.js +++ b/assets/js/servers.js @@ -94,7 +94,7 @@ export class ServerRegistration { this._failedSequentialPings = 0 } - addGraphPoints (points) { + addGraphPoints (points, timestampPoints) { // Test if the first point contains error.placeholder === true // This is sent by the backend when the server hasn't been pinged yet // These points will be disregarded to prevent the graph starting at 0 player count @@ -106,30 +106,33 @@ export class ServerRegistration { points.slice(points.length - SERVER_GRAPH_DATA_MAX_LENGTH, points.length) } - this._graphData = points.map(point => point.result ? [point.timestamp, point.result.players.online] : [point.timestamp, 0]) + for (let i = 0; i < points.length; i++) { + const point = points[i] + const timestamp = timestampPoints[i] + + this._graphData.push([timestamp, point.result ? point.result.players.online : 0]) + } } buildPlotInstance () { this._plotInstance = $.plot('#chart_' + this.serverId, [this._graphData], SERVER_GRAPH_OPTIONS) } - handlePing (payload, timestamp, pushToGraph) { + handlePing (payload, timestamp) { if (payload.result) { this.playerCount = payload.result.players.online - if (pushToGraph) { - // Only update graph for successful pings - // This intentionally pauses the server graph when pings begin to fail - this._graphData.push([timestamp, this.playerCount]) + // Only update graph for successful pings + // This intentionally pauses the server graph when pings begin to fail + this._graphData.push([timestamp, this.playerCount]) - // Trim graphData to within the max length by shifting out the leading elements - if (this._graphData.length > SERVER_GRAPH_DATA_MAX_LENGTH) { - this._graphData.shift() - } - - this.redraw() + // Trim graphData to within the max length by shifting out the leading elements + if (this._graphData.length > SERVER_GRAPH_DATA_MAX_LENGTH) { + this._graphData.shift() } + this.redraw() + // Reset failed ping counter to ensure the next connection error // doesn't instantly retrigger a layout change this._failedSequentialPings = 0 @@ -169,11 +172,7 @@ export class ServerRegistration { this.lastPeakData = data } - updateServerStatus (ping, timestamp, isInitialUpdate, minecraftVersions) { - // Only pushToGraph when initialUpdate === false - // Otherwise the ping value is pushed into the graphData when already present - this.handlePing(ping, timestamp, !isInitialUpdate) - + updateServerStatus (ping, isInitialUpdate, minecraftVersions) { if (ping.versions) { const versionsElement = document.getElementById('version_' + this.serverId) diff --git a/assets/js/socket.js b/assets/js/socket.js index 9a30864..5abd849 100644 --- a/assets/js/socket.js +++ b/assets/js/socket.js @@ -67,7 +67,9 @@ export class SocketManager { } } - payload.servers.forEach(this._app.addServer) + payload.servers.forEach(server => { + this._app.addServer(server, payload.timestampPoints) + }) if (payload.mojangServices) { this._app.mojangUpdater.updateStatus(payload.mojangServices) @@ -88,6 +90,8 @@ export class SocketManager { const serverUpdate = payload.updates[serverId] if (serverRegistration) { + serverRegistration.handlePing(serverUpdate, payload.timestamp) + serverRegistration.updateServerStatus(serverUpdate, payload.timestamp, false, this._app.publicConfig.minecraftVersions) } diff --git a/lib/app.js b/lib/app.js index 820b42d..28a302f 100644 --- a/lib/app.js +++ b/lib/app.js @@ -2,6 +2,7 @@ const Database = require('./database') const MojangUpdater = require('./mojang') const PingController = require('./ping') const Server = require('./server') +const TimeTracker = require('./time') const MessageOf = require('./message') const config = require('../config') @@ -14,6 +15,7 @@ class App { this.mojangUpdater = new MojangUpdater(this) this.pingController = new PingController(this) this.server = new Server(this.handleClientConnection) + this.timeTracker = new TimeTracker() } loadDatabase (callback) { @@ -73,6 +75,7 @@ class App { } })(), mojangServices: this.mojangUpdater.getLastUpdate(), + timestampPoints: this.timeTracker.getPoints(), servers: this.serverRegistrations.map(serverRegistration => serverRegistration.getPingHistory()) } diff --git a/lib/ping.js b/lib/ping.js index 31b0548..a9dda14 100644 --- a/lib/ping.js +++ b/lib/ping.js @@ -97,7 +97,7 @@ class PingController { } pingAll = () => { - const timestamp = new Date().getTime() + const timestamp = this._app.timeTracker.newTimestamp() this.startPingTasks(results => { const updates = [] diff --git a/lib/servers.js b/lib/servers.js index 5d18729..64feaa2 100644 --- a/lib/servers.js +++ b/lib/servers.js @@ -16,7 +16,7 @@ class ServerRegistration { handlePing (timestamp, resp, err, version) { // Store into in-memory ping data - this.addPing(timestamp, resp) + this.addPing(resp) // Only notify the frontend to append to the historical graph // if both the graphing behavior is enabled and the backend agrees @@ -89,10 +89,8 @@ class ServerRegistration { return update } - addPing (timestamp, resp) { - const ping = { - timestamp: timestamp - } + addPing (resp) { + const ping = {} if (resp) { // Append a result object @@ -127,7 +125,6 @@ class ServerRegistration { const payload = { serverId: this.serverId, - timestamp: lastPing.timestamp, versions: this.versions, recordData: this.recordData, favicon: this.lastFavicon @@ -157,7 +154,6 @@ class ServerRegistration { return [{ serverId: this.serverId, - timestamp: new Date().getTime(), error: { message: 'Waiting...', placeholder: true diff --git a/lib/time.js b/lib/time.js new file mode 100644 index 0000000..c820ae6 --- /dev/null +++ b/lib/time.js @@ -0,0 +1,23 @@ +class TimeTracker { + constructor () { + this._points = [] + } + + newTimestamp () { + const timestamp = new Date().getTime() + + this._points.push(timestamp) + + if (this._points.length > 72) { + this._points.shift() + } + + return timestamp + } + + getPoints () { + return this._points + } +} + +module.exports = TimeTracker