remove graph smoothing behavior, add null playerCount support
This commit is contained in:
parent
19190f8d79
commit
ef0c41ee1d
@ -149,7 +149,7 @@ export class GraphDisplayManager {
|
||||
|
||||
let playerCount
|
||||
|
||||
if (id >= serverGraphData.length) {
|
||||
if (id >= serverGraphData.length || typeof serverGraphData[id] !== 'number') {
|
||||
playerCount = '-'
|
||||
} else {
|
||||
playerCount = formatNumber(serverGraphData[id])
|
||||
|
@ -38,6 +38,10 @@ export class RelativeScale {
|
||||
}
|
||||
}
|
||||
|
||||
if (max === Number.MAX_VALUE) {
|
||||
max = 0
|
||||
}
|
||||
|
||||
return RelativeScale.scale([0, max], tickCount)
|
||||
}
|
||||
|
||||
@ -57,6 +61,7 @@ export class RelativeScale {
|
||||
let max = Number.MIN_VALUE
|
||||
|
||||
for (const point of data) {
|
||||
if (typeof point === 'number') {
|
||||
if (point > max) {
|
||||
max = point
|
||||
}
|
||||
@ -64,6 +69,14 @@ export class RelativeScale {
|
||||
min = point
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (min === Number.MAX_VALUE) {
|
||||
min = 0
|
||||
}
|
||||
if (max === Number.MIN_VALUE) {
|
||||
max = 0
|
||||
}
|
||||
|
||||
return [min, max]
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ export class ServerRegistration {
|
||||
this._app = app
|
||||
this.serverId = serverId
|
||||
this.data = data
|
||||
this._graphData = []
|
||||
this._graphData = [[], []]
|
||||
this._failedSequentialPings = 0
|
||||
}
|
||||
|
||||
@ -82,7 +82,16 @@ export class ServerRegistration {
|
||||
plugins: [
|
||||
uPlotTooltipPlugin((pos, id, plot) => {
|
||||
if (pos) {
|
||||
const text = formatNumber(plot.data[1][id]) + ' Players<br>' + formatTimestamp(plot.data[0][id] * 1000)
|
||||
const playerCount = plot.data[1][id]
|
||||
|
||||
if (typeof playerCount !== 'number') {
|
||||
this._app.tooltip.hide()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME: update timestamp schema
|
||||
const text = formatNumber(playerCount) + ' Players<br>' + formatTimestamp(plot.data[0][id] * 1000)
|
||||
|
||||
this._app.tooltip.set(pos.left, pos.top, 10, 10, text)
|
||||
} else {
|
||||
@ -147,13 +156,23 @@ export class ServerRegistration {
|
||||
}
|
||||
|
||||
handlePing (payload, timestamp) {
|
||||
if (typeof payload.playerCount !== 'undefined') {
|
||||
if (typeof payload.playerCount === 'number') {
|
||||
this.playerCount = payload.playerCount
|
||||
|
||||
// Only update graph for successful pings
|
||||
// This intentionally pauses the server graph when pings begin to fail
|
||||
// Reset failed ping counter to ensure the next connection error
|
||||
// doesn't instantly retrigger a layout change
|
||||
this._failedSequentialPings = 0
|
||||
} else {
|
||||
// Attempt to retain a copy of the cached playerCount for up to N failed pings
|
||||
// This prevents minor connection issues from constantly reshuffling the layout
|
||||
if (++this._failedSequentialPings > 5) {
|
||||
this.playerCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Use payload.playerCount so nulls WILL be pushed into the graphing data
|
||||
this._graphData[0].push(Math.floor(timestamp / 1000))
|
||||
this._graphData[1].push(this.playerCount)
|
||||
this._graphData[1].push(payload.playerCount)
|
||||
|
||||
// Trim graphData to within the max length by shifting out the leading elements
|
||||
for (const series of this._graphData) {
|
||||
@ -164,14 +183,18 @@ export class ServerRegistration {
|
||||
|
||||
this.redraw()
|
||||
|
||||
// Reset failed ping counter to ensure the next connection error
|
||||
// doesn't instantly retrigger a layout change
|
||||
this._failedSequentialPings = 0
|
||||
} else {
|
||||
// Attempt to retain a copy of the cached playerCount for up to N failed pings
|
||||
// This prevents minor connection issues from constantly reshuffling the layout
|
||||
if (++this._failedSequentialPings > 5) {
|
||||
this.playerCount = 0
|
||||
if (typeof payload.playerCount !== 'undefined') {
|
||||
this.playerCount = payload.playerCount || 0
|
||||
|
||||
// Use payload.playerCount so nulls WILL be pushed into the graphing data
|
||||
this._graphData[0].push(Math.floor(timestamp / 1000))
|
||||
this._graphData[1].push(payload.playerCount)
|
||||
|
||||
// Trim graphData to within the max length by shifting out the leading elements
|
||||
for (const series of this._graphData) {
|
||||
if (series.length > this._app.publicConfig.serverGraphMaxLength) {
|
||||
series.shift()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,13 +260,23 @@ export class ServerRegistration {
|
||||
const playerCountLabelElement = document.getElementById('player-count_' + this.serverId)
|
||||
const errorElement = document.getElementById('error_' + this.serverId)
|
||||
|
||||
if (ping.error) {
|
||||
if (ping.error || typeof ping.playerCount !== 'number') {
|
||||
// Hide any visible player-count and show the error element
|
||||
playerCountLabelElement.style.display = 'none'
|
||||
errorElement.style.display = 'block'
|
||||
|
||||
errorElement.innerText = ping.error.message
|
||||
} else if (typeof ping.playerCount !== 'undefined') {
|
||||
let errorMessage
|
||||
|
||||
if (ping.error) {
|
||||
errorMessage = ping.error.message
|
||||
} else if (typeof ping.playerCount !== 'number') {
|
||||
// If the frontend has freshly connection, and the server's last ping was in error, it may not contain an error object
|
||||
// In this case playerCount will safely be null, so provide a generic error message instead
|
||||
errorMessage = 'Failed to ping'
|
||||
}
|
||||
|
||||
errorElement.innerText = errorMessage
|
||||
} else if (typeof ping.playerCount === 'number') {
|
||||
// Ensure the player-count element is visible and hide the error element
|
||||
playerCountLabelElement.style.display = 'block'
|
||||
errorElement.style.display = 'none'
|
||||
|
@ -92,8 +92,9 @@ class PingController {
|
||||
const result = results[serverRegistration.serverId]
|
||||
|
||||
// Log to database if enabled
|
||||
// Use null to represent a failed ping
|
||||
if (config.logToDatabase) {
|
||||
const playerCount = result.resp ? result.resp.players.online : 0
|
||||
const playerCount = result.resp ? result.resp.players.online : null
|
||||
|
||||
this._app.database.insertPing(serverRegistration.data.ip, timestamp, playerCount)
|
||||
}
|
||||
@ -130,6 +131,12 @@ class PingController {
|
||||
const version = serverRegistration.getNextProtocolVersion()
|
||||
|
||||
ping(serverRegistration, config.rates.connectTimeout, (err, resp) => {
|
||||
if (Math.random() < 0.1) {
|
||||
err = {
|
||||
message: 'random fail'
|
||||
}
|
||||
resp = undefined
|
||||
}
|
||||
if (err) {
|
||||
logger.log('error', 'Failed to ping %s: %s', serverRegistration.data.ip, err.message)
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ class ServerRegistration {
|
||||
}
|
||||
|
||||
handlePing (timestamp, resp, err, version) {
|
||||
const playerCount = resp ? resp.players.online : 0
|
||||
// Use null to represent a failed ping
|
||||
const playerCount = resp ? resp.players.online : null
|
||||
|
||||
// Store into in-memory ping data
|
||||
this._pingHistory.push(playerCount)
|
||||
@ -37,7 +38,7 @@ class ServerRegistration {
|
||||
let updateHistoryGraph = false
|
||||
|
||||
if (config.logToDatabase) {
|
||||
if (this.addGraphPoint(resp !== undefined, playerCount, timestamp)) {
|
||||
if (this.addGraphPoint(playerCount, timestamp)) {
|
||||
updateHistoryGraph = true
|
||||
}
|
||||
}
|
||||
@ -142,37 +143,21 @@ class ServerRegistration {
|
||||
for (const point of points) {
|
||||
// 0 is the index of the timestamp
|
||||
if (point[0] - lastTimestamp >= 60 * 1000) {
|
||||
// This check tries to smooth out randomly dropped pings
|
||||
// By default only filter pings that are online (playerCount > 0)
|
||||
// This will keep looking forward until it finds a ping that is online
|
||||
// If it can't find one within a reasonable timeframe, it will select a failed ping
|
||||
if (point[0] - lastTimestamp >= 120 * 1000 || point[1] > 0) {
|
||||
minutePoints.push(point)
|
||||
lastTimestamp = point[0]
|
||||
}
|
||||
|
||||
// FIXME: update schema, remove timestamp
|
||||
minutePoints.push(point)
|
||||
}
|
||||
}
|
||||
|
||||
if (minutePoints.length > 0) {
|
||||
this.graphData = minutePoints
|
||||
|
||||
// Select the last entry to use for lastGraphDataPush
|
||||
this._lastGraphDataPush = minutePoints[minutePoints.length - 1][0]
|
||||
}
|
||||
}
|
||||
|
||||
addGraphPoint (isSuccess, playerCount, timestamp) {
|
||||
// If the ping failed, then to avoid destroying the graph, ignore it
|
||||
// However if it's been too long since the last successful ping, push it anyways
|
||||
if (this._lastGraphDataPush) {
|
||||
const timeSince = timestamp - this._lastGraphDataPush
|
||||
if ((isSuccess && timeSince < 60 * 1000) || (!isSuccess && timeSince < 70 * 1000)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
addGraphPoint (playerCount, timestamp) {
|
||||
// FIXME: update schema, remove timestamp
|
||||
this.graphData.push([timestamp, playerCount])
|
||||
this._lastGraphDataPush = timestamp
|
||||
|
||||
// Trim old graphPoints according to #getMaxGraphDataLength
|
||||
if (this.graphData.length > TimeTracker.getMaxGraphDataLength()) {
|
||||
|
Loading…
Reference in New Issue
Block a user