use a single, shared timestamps array between all pings

This commit is contained in:
Nick Krecklow 2020-05-08 01:22:07 -05:00
parent 3ddb2c9a08
commit c2494af82d
No known key found for this signature in database
GPG Key ID: 5F149FDE156FFA94
7 changed files with 55 additions and 30 deletions

@ -102,7 +102,7 @@ export class App {
.reduce((sum, current) => sum + current, 0) .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. // Even if the backend has never pinged the server, the frontend is promised a placeholder object.
// result = undefined // result = undefined
// error = defined with "Waiting" description // error = defined with "Waiting" description
@ -114,14 +114,14 @@ export class App {
// Push the historical data into the graph // 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 // 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 // Create the plot instance internally with the restructured and cleaned data
serverRegistration.buildPlotInstance() serverRegistration.buildPlotInstance()
// Handle the last known state (if any) as an incoming update // Handle the last known state (if any) as an incoming update
// This triggers the main update pipeline and enables centralized update handling // 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 // Allow the ServerRegistration to bind any DOM events with app instance context
serverRegistration.initEventListeners() serverRegistration.initEventListeners()

@ -94,7 +94,7 @@ export class ServerRegistration {
this._failedSequentialPings = 0 this._failedSequentialPings = 0
} }
addGraphPoints (points) { addGraphPoints (points, timestampPoints) {
// Test if the first point contains error.placeholder === true // Test if the first point contains error.placeholder === true
// This is sent by the backend when the server hasn't been pinged yet // 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 // 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) 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 () { buildPlotInstance () {
this._plotInstance = $.plot('#chart_' + this.serverId, [this._graphData], SERVER_GRAPH_OPTIONS) this._plotInstance = $.plot('#chart_' + this.serverId, [this._graphData], SERVER_GRAPH_OPTIONS)
} }
handlePing (payload, timestamp, pushToGraph) { handlePing (payload, timestamp) {
if (payload.result) { if (payload.result) {
this.playerCount = payload.result.players.online this.playerCount = payload.result.players.online
if (pushToGraph) { // Only update graph for successful pings
// Only update graph for successful pings // This intentionally pauses the server graph when pings begin to fail
// This intentionally pauses the server graph when pings begin to fail this._graphData.push([timestamp, this.playerCount])
this._graphData.push([timestamp, this.playerCount])
// Trim graphData to within the max length by shifting out the leading elements // Trim graphData to within the max length by shifting out the leading elements
if (this._graphData.length > SERVER_GRAPH_DATA_MAX_LENGTH) { if (this._graphData.length > SERVER_GRAPH_DATA_MAX_LENGTH) {
this._graphData.shift() this._graphData.shift()
}
this.redraw()
} }
this.redraw()
// Reset failed ping counter to ensure the next connection error // Reset failed ping counter to ensure the next connection error
// doesn't instantly retrigger a layout change // doesn't instantly retrigger a layout change
this._failedSequentialPings = 0 this._failedSequentialPings = 0
@ -169,11 +172,7 @@ export class ServerRegistration {
this.lastPeakData = data this.lastPeakData = data
} }
updateServerStatus (ping, timestamp, isInitialUpdate, minecraftVersions) { updateServerStatus (ping, isInitialUpdate, minecraftVersions) {
// Only pushToGraph when initialUpdate === false
// Otherwise the ping value is pushed into the graphData when already present
this.handlePing(ping, timestamp, !isInitialUpdate)
if (ping.versions) { if (ping.versions) {
const versionsElement = document.getElementById('version_' + this.serverId) const versionsElement = document.getElementById('version_' + this.serverId)

@ -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) { if (payload.mojangServices) {
this._app.mojangUpdater.updateStatus(payload.mojangServices) this._app.mojangUpdater.updateStatus(payload.mojangServices)
@ -88,6 +90,8 @@ export class SocketManager {
const serverUpdate = payload.updates[serverId] const serverUpdate = payload.updates[serverId]
if (serverRegistration) { if (serverRegistration) {
serverRegistration.handlePing(serverUpdate, payload.timestamp)
serverRegistration.updateServerStatus(serverUpdate, payload.timestamp, false, this._app.publicConfig.minecraftVersions) serverRegistration.updateServerStatus(serverUpdate, payload.timestamp, false, this._app.publicConfig.minecraftVersions)
} }

@ -2,6 +2,7 @@ const Database = require('./database')
const MojangUpdater = require('./mojang') const MojangUpdater = require('./mojang')
const PingController = require('./ping') const PingController = require('./ping')
const Server = require('./server') const Server = require('./server')
const TimeTracker = require('./time')
const MessageOf = require('./message') const MessageOf = require('./message')
const config = require('../config') const config = require('../config')
@ -14,6 +15,7 @@ class App {
this.mojangUpdater = new MojangUpdater(this) this.mojangUpdater = new MojangUpdater(this)
this.pingController = new PingController(this) this.pingController = new PingController(this)
this.server = new Server(this.handleClientConnection) this.server = new Server(this.handleClientConnection)
this.timeTracker = new TimeTracker()
} }
loadDatabase (callback) { loadDatabase (callback) {
@ -73,6 +75,7 @@ class App {
} }
})(), })(),
mojangServices: this.mojangUpdater.getLastUpdate(), mojangServices: this.mojangUpdater.getLastUpdate(),
timestampPoints: this.timeTracker.getPoints(),
servers: this.serverRegistrations.map(serverRegistration => serverRegistration.getPingHistory()) servers: this.serverRegistrations.map(serverRegistration => serverRegistration.getPingHistory())
} }

@ -97,7 +97,7 @@ class PingController {
} }
pingAll = () => { pingAll = () => {
const timestamp = new Date().getTime() const timestamp = this._app.timeTracker.newTimestamp()
this.startPingTasks(results => { this.startPingTasks(results => {
const updates = [] const updates = []

@ -16,7 +16,7 @@ class ServerRegistration {
handlePing (timestamp, resp, err, version) { handlePing (timestamp, resp, err, version) {
// Store into in-memory ping data // Store into in-memory ping data
this.addPing(timestamp, resp) this.addPing(resp)
// Only notify the frontend to append to the historical graph // Only notify the frontend to append to the historical graph
// if both the graphing behavior is enabled and the backend agrees // if both the graphing behavior is enabled and the backend agrees
@ -89,10 +89,8 @@ class ServerRegistration {
return update return update
} }
addPing (timestamp, resp) { addPing (resp) {
const ping = { const ping = {}
timestamp: timestamp
}
if (resp) { if (resp) {
// Append a result object // Append a result object
@ -127,7 +125,6 @@ class ServerRegistration {
const payload = { const payload = {
serverId: this.serverId, serverId: this.serverId,
timestamp: lastPing.timestamp,
versions: this.versions, versions: this.versions,
recordData: this.recordData, recordData: this.recordData,
favicon: this.lastFavicon favicon: this.lastFavicon
@ -157,7 +154,6 @@ class ServerRegistration {
return [{ return [{
serverId: this.serverId, serverId: this.serverId,
timestamp: new Date().getTime(),
error: { error: {
message: 'Waiting...', message: 'Waiting...',
placeholder: true placeholder: true

23
lib/time.js Normal file

@ -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