diff --git a/app.js b/app.js index dfd65d4..005bc5d 100644 --- a/app.js +++ b/app.js @@ -93,9 +93,7 @@ function pingAll() { lastGraphPush[network.ip] = timeMs; // Don't have too much data! - if (graphData[network.ip].length >= 24 * 60) { - graphData[network.ip].shift(); - } + util.trimOldPings(graphData); graphData[network.ip].push([timeMs, res ? res.players.online : 0]); @@ -139,6 +137,8 @@ function startServices() { logger.log('info', 'Accepted connection: %s, total clients: %d', client.request.connection.remoteAddress, connectedClients); setTimeout(function() { + client.emit('setGraphDuration', config.graphDuration); + // Send them our previous data, so they have somewhere to start. client.emit('updateMojangServices', mojang.toMessage()); @@ -178,7 +178,7 @@ if (config.logToDatabase) { var timestamp = util.getCurrentTimeMs(); - db.queryPings(24 * 60 * 60 * 1000, function(data) { + db.queryPings(config.graphDuration, function(data) { graphData = util.convertPingsToGraph(data); logger.log('info', 'Queried and parsed ping history in %sms', util.getCurrentTimeMs() - timestamp); @@ -186,7 +186,7 @@ if (config.logToDatabase) { startServices(); }); } else { - logger.warn('Database logging is not enabled. You can enable it by setting "logToDatabase" to true in config.json. This requires sqlite3 to be installed.'); + logger.log('warn', 'Database logging is not enabled. You can enable it by setting "logToDatabase" to true in config.json. This requires sqlite3 to be installed.'); startServices(); } \ No newline at end of file diff --git a/assets/js/site.js b/assets/js/site.js index fe0b528..318c3d6 100644 --- a/assets/js/site.js +++ b/assets/js/site.js @@ -231,6 +231,8 @@ $(document).ready(function() { var mojangServicesUpdater; var sortServersTask; + var graphDuration; + socket.on('connect', function() { $('#tagline-text').text('Loading...'); @@ -262,6 +264,10 @@ $(document).ready(function() { $('#big-graph-controls').css('display', 'none'); }); + socket.on('setGraphDuration', function(value) { + graphDuration = value; + }); + socket.on('historyGraph', function(rawData) { displayedGraphData = rawData; @@ -295,23 +301,25 @@ $(document).ready(function() { }); socket.on('updateHistoryGraph', function(rawData) { - var targetGraphData = displayedGraphData[rawData.ip]; - - // If it's not in our display group, push it to the hidden group instead so it can be restored and still be up to date. - if (!targetGraphData) { - targetGraphData = hiddenGraphData[rawData.ip]; + // Prevent race conditions. + if (!graphDuration) { + return; } - if (targetGraphData.length > 24 * 60) { - targetGraphData.shift(); + // If it's not in our display group, use the hidden group instead. + var targetGraphData = displayedGraphData[rawData.ip] ? displayedGraphData : hiddenGraphData; + + trimOldPings(targetGraphData, graphDuration); + + targetGraphData[rawData.ip].push([rawData.timestamp, rawData.players]); + + // Redraw if we need to. + if (displayedGraphData[rawData.ip]) { + historyPlot.setData(convertGraphData(displayedGraphData)); + historyPlot.setupGrid(); + + historyPlot.draw(); } - - targetGraphData.push([rawData.timestamp, rawData.players]); - - historyPlot.setData(convertGraphData(displayedGraphData)); - historyPlot.setupGrid(); - - historyPlot.draw(); }); socket.on('add', function(servers) { diff --git a/assets/js/util.js b/assets/js/util.js index 5184d55..b128990 100644 --- a/assets/js/util.js +++ b/assets/js/util.js @@ -36,6 +36,30 @@ function isMobileBrowser() { return check; } +function trimOldPings(data, graphDuration) { + var keys = Object.keys(data); + + var timeMs = new Date().getTime(); + + for (var x = 0; x < keys.length; x++) { + var listing = data[keys[x]]; + + var toSplice = []; + + for (var i = 0; i < listing.length; i++) { + var entry = listing[i]; + + if (timeMs - entry[0] > graphDuration) { + toSplice.push(i); + } + } + + for (var i = 0; i < toSplice.length; i++) { + listing.splice(toSplice[i], 1); + } + } +} + function handlePlotHover(event, pos, item) { if (item) { var text = getTimestamp(item.datapoint[0] / 1000) + '\ diff --git a/config.json b/config.json index 5bc77d9..f9558e0 100644 --- a/config.json +++ b/config.json @@ -188,5 +188,6 @@ "pingAll": 2000, "connectTimeout": 1500 }, - "logToDatabase": true + "logToDatabase": true, + "graphDuration": 86400000 } diff --git a/lib/server.js b/lib/server.js index 35cf1e6..40c494f 100644 --- a/lib/server.js +++ b/lib/server.js @@ -27,6 +27,7 @@ exports.start = function(callback) { if (requestUrl === '/status.json') { res.setHeader('Content-Type', 'text/plain'); + res.write(JSON.stringify({ error: true, message: 'API deprecated.' @@ -41,6 +42,7 @@ exports.start = function(callback) { fs.createReadStream(file).pipe(res); } else { res.statusCode = 404; + res.write('404'); res.end(); @@ -50,8 +52,7 @@ exports.start = function(callback) { server.listen(config.site.port, config.site.ip); // I don't like this. But it works, I think. - io = io.listen(server); - exports.io = io; + exports.io = io.listen(server); // Since everything is loaded, do some final prep work. logger.log('info', 'Started on %s:%d', config.site.ip, config.site.port); diff --git a/lib/util.js b/lib/util.js index e730e60..a575409 100644 --- a/lib/util.js +++ b/lib/util.js @@ -61,6 +61,29 @@ function trimUselessPings(data) { } } +exports.trimOldPings = function(data) { + var keys = Object.keys(data); + + var timeMs = exports.getCurrentTimeMs(); + + for (var x = 0; x < keys.length; x++) { + var listing = data[keys[x]]; + var toSplice = []; + + for (var i = 0; i < listing.length; i++) { + var entry = listing[i]; + + if (timeMs - entry[0] > config.graphDuration) { + toSplice.push(i); + } + } + + for (var i = 0; i < toSplice.length; i++) { + listing.splice(toSplice[i], 1); + } + } +} + exports.getCurrentTimeMs = function() { return new Date().getTime(); }; @@ -89,5 +112,8 @@ exports.convertPingsToGraph = function(sqlData) { // Break it into minutes. trimUselessPings(graphData); + // Drop old data. + exports.trimOldPings(graphData); + return graphData; }; \ No newline at end of file