commit
c2dd49bf15
5
CHANGELOG.md
Normal file
5
CHANGELOG.md
Normal file
@ -0,0 +1,5 @@
|
||||
**2.0.0**
|
||||
- Servers are now referenced by their name on the graph controls instead of their IP.
|
||||
- Servers now display their name on hover instead of their IP.
|
||||
- Graph controls are now saved and loaded automatically.
|
||||
- Moved server configuration into servers.json from config.json.
|
@ -16,6 +16,9 @@ You can see an up-to-date copy of the master branch running on http://minetrack.
|
||||
Database logging is disabled by default. You can enable it in ```config.json``` by setting ```logToDatabase``` to true.
|
||||
This requires sqlite3 drivers to be installed.
|
||||
|
||||
#### What's being changed?
|
||||
For the changelog, check out the [CHANGELOG](CHANGELOG.md) file.
|
||||
|
||||
#### How do I get added?
|
||||
At the moment, the main "minetrack.me" site is only accepting networks that average roughly 1,000 players at peak for **PC** servers, and 100 players at peak for **PE** servers. This is due to limited capacity and it's functionality. If you fit this description, you're welcome to open a Pull Request adding the network to ```config.json```.
|
||||
|
||||
|
7
app.js
7
app.js
@ -104,15 +104,16 @@ function handlePing(network, res, err) {
|
||||
// Don't have too much data!
|
||||
util.trimOldPings(graphData);
|
||||
|
||||
if (!graphData[network.ip]) {
|
||||
graphData[network.ip] = [];
|
||||
if (!graphData[network.name]) {
|
||||
graphData[network.name] = [];
|
||||
}
|
||||
|
||||
graphData[network.ip].push([timeMs, res ? res.players.online : 0]);
|
||||
graphData[network.name].push([timeMs, res ? res.players.online : 0]);
|
||||
|
||||
// Send the update.
|
||||
server.io.sockets.emit('updateHistoryGraph', {
|
||||
ip: network.ip,
|
||||
name: network.name,
|
||||
players: (res ? res.players.online : 0),
|
||||
timestamp: timeMs
|
||||
});
|
||||
|
@ -214,6 +214,13 @@ function setAllGraphVisibility(visible) {
|
||||
historyPlot.setupGrid();
|
||||
|
||||
historyPlot.draw();
|
||||
|
||||
// Update our localStorage
|
||||
if (visible) {
|
||||
resetGraphControls();
|
||||
} else {
|
||||
saveGraphControls(Object.keys(displayedGraphData));
|
||||
}
|
||||
}
|
||||
|
||||
function toggleControlsDrawer() {
|
||||
@ -270,11 +277,30 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
socket.on('historyGraph', function(rawData) {
|
||||
displayedGraphData = rawData;
|
||||
var shownServers = loadGraphControls();
|
||||
|
||||
if (shownServers) {
|
||||
var keys = Object.keys(rawData);
|
||||
|
||||
hiddenGraphData = [];
|
||||
displayedGraphData = [];
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var name = keys[i];
|
||||
|
||||
if (shownServers.indexOf(name) !== -1) {
|
||||
displayedGraphData[name] = rawData[name];
|
||||
} else {
|
||||
hiddenGraphData[name] = rawData[name];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
displayedGraphData = rawData;
|
||||
}
|
||||
|
||||
$('#big-graph').css('height', '400px');
|
||||
|
||||
historyPlot = $.plot('#big-graph', convertGraphData(rawData), bigChartOptions);
|
||||
historyPlot = $.plot('#big-graph', convertGraphData(displayedGraphData), bigChartOptions);
|
||||
|
||||
$('#big-graph').bind('plothover', handlePlotHover);
|
||||
|
||||
@ -286,7 +312,13 @@ $(document).ready(function() {
|
||||
keys.sort();
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
html += '<td><input type="checkbox" class="graph-control" id="graph-controls" data-target-network="' + keys[i] + '" checked=checked> ' + keys[i] + '</input></td>';
|
||||
var checkedString = '';
|
||||
|
||||
if (displayedGraphData[keys[i]]) {
|
||||
checkedString = 'checked=checked';
|
||||
}
|
||||
|
||||
html += '<td><input type="checkbox" class="graph-control" id="graph-controls" data-target-network="' + keys[i] + '" ' + checkedString + '> ' + keys[i] + '</input></td>';
|
||||
|
||||
if (sinceBreak >= 7) {
|
||||
sinceBreak = 0;
|
||||
@ -303,19 +335,19 @@ $(document).ready(function() {
|
||||
|
||||
socket.on('updateHistoryGraph', function(rawData) {
|
||||
// Prevent race conditions.
|
||||
if (!graphDuration) {
|
||||
if (!graphDuration || !displayedGraphData || !hiddenGraphData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's not in our display group, use the hidden group instead.
|
||||
var targetGraphData = displayedGraphData[rawData.ip] ? displayedGraphData : hiddenGraphData;
|
||||
var targetGraphData = displayedGraphData[rawData.name] ? displayedGraphData : hiddenGraphData;
|
||||
|
||||
trimOldPings(targetGraphData, graphDuration);
|
||||
|
||||
targetGraphData[rawData.ip].push([rawData.timestamp, rawData.players]);
|
||||
targetGraphData[rawData.name].push([rawData.timestamp, rawData.players]);
|
||||
|
||||
// Redraw if we need to.
|
||||
if (displayedGraphData[rawData.ip]) {
|
||||
if (displayedGraphData[rawData.name]) {
|
||||
historyPlot.setData(convertGraphData(displayedGraphData));
|
||||
historyPlot.setupGrid();
|
||||
|
||||
@ -460,9 +492,17 @@ $(document).ready(function() {
|
||||
delete hiddenGraphData[serverIp];
|
||||
}
|
||||
|
||||
// Redraw the graph
|
||||
historyPlot.setData(convertGraphData(displayedGraphData));
|
||||
historyPlot.setupGrid();
|
||||
|
||||
historyPlot.draw();
|
||||
|
||||
// Update our localStorage
|
||||
if (Object.keys(hiddenGraphData).length === 0) {
|
||||
resetGraphControls();
|
||||
} else {
|
||||
saveGraphControls(Object.keys(displayedGraphData));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,30 @@ var MISSING_FAVICON_BASE64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAA
|
||||
|
||||
var tooltip = $('#tooltip');
|
||||
|
||||
function saveGraphControls(displayedServers) {
|
||||
if (typeof(localStorage) !== undefined) {
|
||||
var json = JSON.stringify(displayedServers);
|
||||
|
||||
localStorage.setItem('displayedServers', json);
|
||||
}
|
||||
}
|
||||
|
||||
function loadGraphControls() {
|
||||
if (typeof(localStorage) !== undefined) {
|
||||
var item = localStorage.getItem('displayedServers');
|
||||
|
||||
if (item) {
|
||||
return JSON.parse(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetGraphControls() {
|
||||
if (typeof(localStorage) !== undefined) {
|
||||
localStorage.removeItem('displayedServers');
|
||||
}
|
||||
}
|
||||
|
||||
function getTimestamp(ms, timeOnly) {
|
||||
var date = new Date(0);
|
||||
|
||||
@ -96,7 +120,7 @@ function convertGraphData(rawData) {
|
||||
function stringToColor(base) {
|
||||
var hash;
|
||||
|
||||
for (var i = 0, hash = 0; i < base.length; i++) {
|
||||
for (var i = base.length - 1, hash = 0; i >= 0; i--) {
|
||||
hash = base.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
|
||||
|
61
lib/util.js
61
lib/util.js
@ -1,17 +1,39 @@
|
||||
var logger = require('./logger');
|
||||
|
||||
var config = require('../config.json');
|
||||
var servers = require('../servers.json');
|
||||
|
||||
// Checks if we have a server in config.json with the IP.
|
||||
function serverWithIpExists(ip) {
|
||||
var serverNameLookup = {};
|
||||
|
||||
// Finds a server in servers.json with a matching IP.
|
||||
// If it finds one, it caches the result for faster future lookups.
|
||||
function getServerNameByIp(ip) {
|
||||
var lookupName = serverNameLookup[ip];
|
||||
|
||||
if (lookupName) {
|
||||
return lookupName;
|
||||
}
|
||||
|
||||
for (var i = 0; i < servers.length; i++) {
|
||||
var entry = servers[i];
|
||||
|
||||
if (entry.ip === ip) {
|
||||
return true;
|
||||
serverNameLookup[entry.ip] = entry.name;
|
||||
|
||||
return entry.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// Returns a list of configured server IPs from servers.json
|
||||
function getServerIps() {
|
||||
var ips = [];
|
||||
|
||||
for (var i = 0; i < servers.length; i++) {
|
||||
ips.push(servers[i].ip);
|
||||
}
|
||||
|
||||
return ips;
|
||||
}
|
||||
|
||||
// This method is a monstrosity.
|
||||
@ -20,16 +42,7 @@ function serverWithIpExists(ip) {
|
||||
function trimUselessPings(data) {
|
||||
var keys = Object.keys(data);
|
||||
|
||||
var keysToRemove = [];
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
// Don't bother we servers we deleted from config.json
|
||||
if (!serverWithIpExists(keys[i])) {
|
||||
keysToRemove.push(keys[i]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var listing = data[keys[i]];
|
||||
var lastTimestamp = 0;
|
||||
|
||||
@ -55,11 +68,6 @@ function trimUselessPings(data) {
|
||||
|
||||
data[keys[i]] = filteredListing;
|
||||
}
|
||||
|
||||
// Delete data for any networks we don't care about anymore.
|
||||
for (var i = 0; i < keysToRemove.length; i++) {
|
||||
delete data[keysToRemove[i]];
|
||||
}
|
||||
}
|
||||
|
||||
exports.trimOldPings = function(data) {
|
||||
@ -98,16 +106,25 @@ exports.setIntervalNoDelay = function(func, delay) {
|
||||
};
|
||||
|
||||
exports.convertPingsToGraph = function(sqlData) {
|
||||
var serverIps = getServerIps();
|
||||
var graphData = {};
|
||||
|
||||
var startTime = exports.getCurrentTimeMs();
|
||||
|
||||
for (var i = 0; i < sqlData.length; i++) {
|
||||
var entry = sqlData[i];
|
||||
|
||||
if (!graphData[entry.ip]) {
|
||||
graphData[entry.ip] = [];
|
||||
if (serverIps.indexOf(entry.ip) === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
graphData[entry.ip].push([entry.timestamp, entry.playerCount]);
|
||||
var name = getServerNameByIp(entry.ip);
|
||||
|
||||
if (!graphData[name]) {
|
||||
graphData[name] = [];
|
||||
}
|
||||
|
||||
graphData[name].push([entry.timestamp, entry.playerCount]);
|
||||
}
|
||||
|
||||
// Break it into minutes.
|
||||
@ -116,5 +133,7 @@ exports.convertPingsToGraph = function(sqlData) {
|
||||
// Drop old data.
|
||||
exports.trimOldPings(graphData);
|
||||
|
||||
logger.info('Converted data structure in ' + (exports.getCurrentTimeMs() - startTime) + 'ms');
|
||||
|
||||
return graphData;
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "minetrack",
|
||||
"version": "1.0.0",
|
||||
"version": "2.0.0",
|
||||
"description": "A Minecraft server tracker that lets you focus on the basics.",
|
||||
"main": "app.js",
|
||||
"dependencies": {
|
||||
|
Loading…
Reference in New Issue
Block a user