share a single timestamp array between all graphData objects
This commit is contained in:
parent
59ec7d151f
commit
c2f6d04e72
@ -344,7 +344,7 @@ footer a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#big-graph {
|
#big-graph {
|
||||||
padding-right: 60px;
|
padding-right: 65px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#big-graph, #big-graph-controls, #big-graph-checkboxes {
|
#big-graph, #big-graph-controls, #big-graph-checkboxes {
|
||||||
|
@ -37,6 +37,11 @@ export class GraphDisplayManager {
|
|||||||
for (let i = 0; i < playerCounts.length; i++) {
|
for (let i = 0; i < playerCounts.length; i++) {
|
||||||
this._graphData[i].push(playerCounts[i])
|
this._graphData[i].push(playerCounts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._plotInstance.setData([
|
||||||
|
this._graphTimestamps,
|
||||||
|
...this._graphData
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
loadLocalStorage () {
|
loadLocalStorage () {
|
||||||
@ -183,7 +188,7 @@ export class GraphDisplayManager {
|
|||||||
{
|
{
|
||||||
font: '14px "Open Sans", sans-serif',
|
font: '14px "Open Sans", sans-serif',
|
||||||
stroke: '#FFF',
|
stroke: '#FFF',
|
||||||
size: 60,
|
size: 65,
|
||||||
grid: {
|
grid: {
|
||||||
stroke: '#333',
|
stroke: '#333',
|
||||||
width: 1
|
width: 1
|
||||||
|
@ -12,7 +12,7 @@ export class RelativeScale {
|
|||||||
|
|
||||||
const ticks = (scaledMax - scaledMin) / scale
|
const ticks = (scaledMax - scaledMin) / scale
|
||||||
|
|
||||||
if (ticks + 1 <= tickCount) {
|
if (ticks < tickCount + 1) {
|
||||||
return [scaledMin, scaledMax, scale]
|
return [scaledMin, scaledMax, scale]
|
||||||
} else {
|
} else {
|
||||||
// Too many steps between min/max, increase factor and try again
|
// Too many steps between min/max, increase factor and try again
|
||||||
|
@ -75,7 +75,7 @@ export class ServerRegistration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildPlotInstance () {
|
buildPlotInstance () {
|
||||||
const tickCount = 5
|
const tickCount = 4
|
||||||
|
|
||||||
// eslint-disable-next-line new-cap
|
// eslint-disable-next-line new-cap
|
||||||
this._plotInstance = new uPlot({
|
this._plotInstance = new uPlot({
|
||||||
|
10
lib/app.js
10
lib/app.js
@ -41,18 +41,14 @@ class App {
|
|||||||
if (config.logToDatabase) {
|
if (config.logToDatabase) {
|
||||||
client.on('message', (message) => {
|
client.on('message', (message) => {
|
||||||
if (message === 'requestHistoryGraph') {
|
if (message === 'requestHistoryGraph') {
|
||||||
// FIXME: update schema, remove timestamp
|
|
||||||
// Since all history graph updates share timestamps, pull the timestamps from a single ServerRegistration
|
|
||||||
const timestamps = this.serverRegistrations[0].graphData.map(point => Math.floor(point[0] / 1000))
|
|
||||||
|
|
||||||
// Send historical graphData built from all serverRegistrations
|
// Send historical graphData built from all serverRegistrations
|
||||||
const graphData = this.serverRegistrations.map(serverRegistration => serverRegistration.graphData.map(point => point[1]))
|
const graphData = this.serverRegistrations.map(serverRegistration => serverRegistration.graphData)
|
||||||
|
|
||||||
// Send graphData in object wrapper to avoid needing to explicity filter
|
// Send graphData in object wrapper to avoid needing to explicity filter
|
||||||
// any header data being appended by #MessageOf since the graph data is fed
|
// any header data being appended by #MessageOf since the graph data is fed
|
||||||
// directly into the graphing system
|
// directly into the graphing system
|
||||||
client.send(MessageOf('historyGraph', {
|
client.send(MessageOf('historyGraph', {
|
||||||
timestamps,
|
timestamps: this.timeTracker.getHistoricalPointsSeconds(),
|
||||||
graphData
|
graphData
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -78,7 +74,7 @@ class App {
|
|||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
mojangServices: this.mojangUpdater.getLastUpdate(),
|
mojangServices: this.mojangUpdater.getLastUpdate(),
|
||||||
timestampPoints: this.timeTracker.getPointsSeconds(),
|
timestampPoints: this.timeTracker.getServerPointsSeconds(),
|
||||||
servers: this.serverRegistrations.map(serverRegistration => serverRegistration.getPingHistory())
|
servers: this.serverRegistrations.map(serverRegistration => serverRegistration.getPingHistory())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,33 +20,63 @@ class Database {
|
|||||||
const startTime = endTime - graphDuration
|
const startTime = endTime - graphDuration
|
||||||
|
|
||||||
this.getRecentPings(startTime, endTime, pingData => {
|
this.getRecentPings(startTime, endTime, pingData => {
|
||||||
const graphPointsByIp = []
|
const relativeGraphData = []
|
||||||
|
|
||||||
for (const row of pingData) {
|
for (const row of pingData) {
|
||||||
// Load into temporary array
|
// Load into temporary array
|
||||||
// This will be culled prior to being pushed to the serverRegistration
|
// This will be culled prior to being pushed to the serverRegistration
|
||||||
let graphPoints = graphPointsByIp[row.ip]
|
let graphData = relativeGraphData[row.ip]
|
||||||
if (!graphPoints) {
|
if (!graphData) {
|
||||||
graphPoints = graphPointsByIp[row.ip] = []
|
relativeGraphData[row.ip] = graphData = [[], []]
|
||||||
}
|
}
|
||||||
|
|
||||||
graphPoints.push([row.timestamp, row.playerCount])
|
// DANGER!
|
||||||
|
// This will pull the timestamp from each row into memory
|
||||||
|
// This is built under the assumption that each round of pings shares the same timestamp
|
||||||
|
// This enables all timestamp arrays to have consistent point selection and graph correctly
|
||||||
|
graphData[0].push(row.timestamp)
|
||||||
|
graphData[1].push(row.playerCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(graphPointsByIp).forEach(ip => {
|
Object.keys(relativeGraphData).forEach(ip => {
|
||||||
// Match IPs to serverRegistration object
|
// Match IPs to serverRegistration object
|
||||||
for (const serverRegistration of this._app.serverRegistrations) {
|
for (const serverRegistration of this._app.serverRegistrations) {
|
||||||
if (serverRegistration.data.ip === ip) {
|
if (serverRegistration.data.ip === ip) {
|
||||||
const graphPoints = graphPointsByIp[ip]
|
const graphData = relativeGraphData[ip]
|
||||||
|
|
||||||
// Push the data into the instance and cull if needed
|
// Push the data into the instance and cull if needed
|
||||||
serverRegistration.loadGraphPoints(graphPoints)
|
serverRegistration.loadGraphPoints(startTime, graphData[0], graphData[1])
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Since all timestamps are shared, use the array from the first ServerRegistration
|
||||||
|
// This is very dangerous and can break if data is out of sync
|
||||||
|
if (Object.keys(relativeGraphData).length > 0) {
|
||||||
|
const serverIp = Object.keys(relativeGraphData)[0]
|
||||||
|
const timestamps = relativeGraphData[serverIp][0]
|
||||||
|
|
||||||
|
// This is a copy of ServerRegistration#loadGraphPoints
|
||||||
|
// relativeGraphData contains original timestamp data and needs to be filtered into minutes
|
||||||
|
const sharedTimestamps = []
|
||||||
|
|
||||||
|
let lastTimestamp = startTime
|
||||||
|
|
||||||
|
for (let i = 0; i < timestamps.length; i++) {
|
||||||
|
const timestamp = timestamps[i]
|
||||||
|
|
||||||
|
if (timestamp - lastTimestamp >= 60 * 1000) {
|
||||||
|
lastTimestamp = timestamp
|
||||||
|
|
||||||
|
sharedTimestamps.push(timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._app.timeTracker.loadHistoricalTimestamps(sharedTimestamps)
|
||||||
|
}
|
||||||
|
|
||||||
callback()
|
callback()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
10
lib/ping.js
10
lib/ping.js
@ -83,15 +83,7 @@ class PingController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pingAll = () => {
|
pingAll = () => {
|
||||||
const timestamp = this._app.timeTracker.newTimestamp()
|
const { timestamp, updateHistoryGraph } = this._app.timeTracker.newPingTimestamp()
|
||||||
|
|
||||||
// Flag each group as history graph additions each minute
|
|
||||||
// This is sent to the frontend for graph updates
|
|
||||||
const updateHistoryGraph = config.logToDatabase && (!this._lastHistoryGraphUpdate || timestamp - this._lastHistoryGraphUpdate >= 60 * 1000)
|
|
||||||
|
|
||||||
if (updateHistoryGraph) {
|
|
||||||
this._lastHistoryGraphUpdate = timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startPingTasks(results => {
|
this.startPingTasks(results => {
|
||||||
const updates = []
|
const updates = []
|
||||||
|
@ -14,7 +14,8 @@ class ServerRegistration {
|
|||||||
recordData
|
recordData
|
||||||
graphData = []
|
graphData = []
|
||||||
|
|
||||||
constructor (serverId, data) {
|
constructor (app, serverId, data) {
|
||||||
|
this._app = app
|
||||||
this.serverId = serverId
|
this.serverId = serverId
|
||||||
this.data = data
|
this.data = data
|
||||||
this._pingHistory = []
|
this._pingHistory = []
|
||||||
@ -36,8 +37,7 @@ class ServerRegistration {
|
|||||||
// if both the graphing behavior is enabled and the backend agrees
|
// if both the graphing behavior is enabled and the backend agrees
|
||||||
// that the ping is eligible for addition
|
// that the ping is eligible for addition
|
||||||
if (updateHistoryGraph) {
|
if (updateHistoryGraph) {
|
||||||
// FIXME: update schema, remove timestamp
|
this.graphData.push(playerCount)
|
||||||
this.graphData.push([timestamp, playerCount])
|
|
||||||
|
|
||||||
// Trim old graphPoints according to #getMaxGraphDataLength
|
// Trim old graphPoints according to #getMaxGraphDataLength
|
||||||
if (this.graphData.length > TimeTracker.getMaxGraphDataLength()) {
|
if (this.graphData.length > TimeTracker.getMaxGraphDataLength()) {
|
||||||
@ -131,31 +131,26 @@ class ServerRegistration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadGraphPoints (points) {
|
loadGraphPoints (startTime, timestamps, points) {
|
||||||
// Filter pings so each result is a minute apart
|
// Filter pings so each result is a minute apart
|
||||||
const minutePoints = []
|
let lastTimestamp = startTime
|
||||||
let lastTimestamp = 0
|
|
||||||
|
|
||||||
for (const point of points) {
|
for (let i = 0; i < timestamps.length; i++) {
|
||||||
// 0 is the index of the timestamp
|
const timestamp = timestamps[i]
|
||||||
if (point[0] - lastTimestamp >= 60 * 1000) {
|
|
||||||
lastTimestamp = point[0]
|
|
||||||
|
|
||||||
// FIXME: update schema, remove timestamp
|
if (timestamp - lastTimestamp >= 60 * 1000) {
|
||||||
minutePoints.push(point)
|
lastTimestamp = timestamp
|
||||||
|
|
||||||
|
this.graphData.push(points[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minutePoints.length > 0) {
|
|
||||||
this.graphData = minutePoints
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findNewGraphPeak () {
|
findNewGraphPeak () {
|
||||||
let index = -1
|
let index = -1
|
||||||
for (let i = 0; i < this.graphData.length; i++) {
|
for (let i = 0; i < this.graphData.length; i++) {
|
||||||
const point = this.graphData[i]
|
const point = this.graphData[i]
|
||||||
if (index === -1 || point[1] > this.graphData[index][1]) {
|
if (index === -1 || point > this.graphData[index]) {
|
||||||
index = i
|
index = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,10 +168,9 @@ class ServerRegistration {
|
|||||||
if (this._graphPeakIndex === undefined) {
|
if (this._graphPeakIndex === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const graphPeak = this.graphData[this._graphPeakIndex]
|
|
||||||
return {
|
return {
|
||||||
playerCount: graphPeak[1],
|
playerCount: this.graphData[this._graphPeakIndex],
|
||||||
timestamp: Math.floor(graphPeak[0] / 1000)
|
timestamp: this._app.timeTracker.getHistoricalPointSeconds(this._graphPeakIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
lib/time.js
37
lib/time.js
@ -4,9 +4,10 @@ class TimeTracker {
|
|||||||
constructor (app) {
|
constructor (app) {
|
||||||
this._app = app
|
this._app = app
|
||||||
this._points = []
|
this._points = []
|
||||||
|
this._historicalTimestamps = []
|
||||||
}
|
}
|
||||||
|
|
||||||
newTimestamp () {
|
newPingTimestamp () {
|
||||||
const timestamp = new Date().getTime()
|
const timestamp = new Date().getTime()
|
||||||
|
|
||||||
this._points.push(timestamp)
|
this._points.push(timestamp)
|
||||||
@ -15,10 +16,40 @@ class TimeTracker {
|
|||||||
this._points.shift()
|
this._points.shift()
|
||||||
}
|
}
|
||||||
|
|
||||||
return timestamp
|
// Flag each group as history graph additions each minute
|
||||||
|
// This is sent to the frontend for graph updates
|
||||||
|
const updateHistoryGraph = config.logToDatabase && (!this._lastHistoryGraphUpdate || timestamp - this._lastHistoryGraphUpdate >= 60 * 1000)
|
||||||
|
|
||||||
|
if (updateHistoryGraph) {
|
||||||
|
this._lastHistoryGraphUpdate = timestamp
|
||||||
|
|
||||||
|
// Push into timestamps array to update backend state
|
||||||
|
this._historicalTimestamps.push(timestamp)
|
||||||
|
|
||||||
|
if (this._historicalTimestamps.length > TimeTracker.getMaxGraphDataLength()) {
|
||||||
|
this._historicalTimestamps.shift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
timestamp,
|
||||||
|
updateHistoryGraph
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPointsSeconds () {
|
loadHistoricalTimestamps (timestamps) {
|
||||||
|
this._historicalTimestamps = timestamps
|
||||||
|
}
|
||||||
|
|
||||||
|
getHistoricalPointsSeconds () {
|
||||||
|
return this._historicalTimestamps.map(value => Math.floor(value / 1000))
|
||||||
|
}
|
||||||
|
|
||||||
|
getHistoricalPointSeconds (index) {
|
||||||
|
return Math.floor(this._historicalTimestamps[index] / 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
getServerPointsSeconds () {
|
||||||
return this._points.map(value => Math.floor(value / 1000))
|
return this._points.map(value => Math.floor(value / 1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
main.js
2
main.js
@ -22,7 +22,7 @@ servers.forEach((server, serverId) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init a ServerRegistration instance of each entry in servers.json
|
// Init a ServerRegistration instance of each entry in servers.json
|
||||||
app.serverRegistrations.push(new ServerRegistration(serverId, server))
|
app.serverRegistrations.push(new ServerRegistration(app, serverId, server))
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!config.serverGraphDuration) {
|
if (!config.serverGraphDuration) {
|
||||||
|
Loading…
Reference in New Issue
Block a user