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.
|
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.
|
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?
|
#### 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```.
|
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!
|
// Don't have too much data!
|
||||||
util.trimOldPings(graphData);
|
util.trimOldPings(graphData);
|
||||||
|
|
||||||
if (!graphData[network.ip]) {
|
if (!graphData[network.name]) {
|
||||||
graphData[network.ip] = [];
|
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.
|
// Send the update.
|
||||||
server.io.sockets.emit('updateHistoryGraph', {
|
server.io.sockets.emit('updateHistoryGraph', {
|
||||||
ip: network.ip,
|
ip: network.ip,
|
||||||
|
name: network.name,
|
||||||
players: (res ? res.players.online : 0),
|
players: (res ? res.players.online : 0),
|
||||||
timestamp: timeMs
|
timestamp: timeMs
|
||||||
});
|
});
|
||||||
|
@ -214,6 +214,13 @@ function setAllGraphVisibility(visible) {
|
|||||||
historyPlot.setupGrid();
|
historyPlot.setupGrid();
|
||||||
|
|
||||||
historyPlot.draw();
|
historyPlot.draw();
|
||||||
|
|
||||||
|
// Update our localStorage
|
||||||
|
if (visible) {
|
||||||
|
resetGraphControls();
|
||||||
|
} else {
|
||||||
|
saveGraphControls(Object.keys(displayedGraphData));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleControlsDrawer() {
|
function toggleControlsDrawer() {
|
||||||
@ -270,11 +277,30 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('historyGraph', function(rawData) {
|
socket.on('historyGraph', function(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;
|
displayedGraphData = rawData;
|
||||||
|
}
|
||||||
|
|
||||||
$('#big-graph').css('height', '400px');
|
$('#big-graph').css('height', '400px');
|
||||||
|
|
||||||
historyPlot = $.plot('#big-graph', convertGraphData(rawData), bigChartOptions);
|
historyPlot = $.plot('#big-graph', convertGraphData(displayedGraphData), bigChartOptions);
|
||||||
|
|
||||||
$('#big-graph').bind('plothover', handlePlotHover);
|
$('#big-graph').bind('plothover', handlePlotHover);
|
||||||
|
|
||||||
@ -286,7 +312,13 @@ $(document).ready(function() {
|
|||||||
keys.sort();
|
keys.sort();
|
||||||
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
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) {
|
if (sinceBreak >= 7) {
|
||||||
sinceBreak = 0;
|
sinceBreak = 0;
|
||||||
@ -303,19 +335,19 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
socket.on('updateHistoryGraph', function(rawData) {
|
socket.on('updateHistoryGraph', function(rawData) {
|
||||||
// Prevent race conditions.
|
// Prevent race conditions.
|
||||||
if (!graphDuration) {
|
if (!graphDuration || !displayedGraphData || !hiddenGraphData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's not in our display group, use the hidden group instead.
|
// 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);
|
trimOldPings(targetGraphData, graphDuration);
|
||||||
|
|
||||||
targetGraphData[rawData.ip].push([rawData.timestamp, rawData.players]);
|
targetGraphData[rawData.name].push([rawData.timestamp, rawData.players]);
|
||||||
|
|
||||||
// Redraw if we need to.
|
// Redraw if we need to.
|
||||||
if (displayedGraphData[rawData.ip]) {
|
if (displayedGraphData[rawData.name]) {
|
||||||
historyPlot.setData(convertGraphData(displayedGraphData));
|
historyPlot.setData(convertGraphData(displayedGraphData));
|
||||||
historyPlot.setupGrid();
|
historyPlot.setupGrid();
|
||||||
|
|
||||||
@ -460,9 +492,17 @@ $(document).ready(function() {
|
|||||||
delete hiddenGraphData[serverIp];
|
delete hiddenGraphData[serverIp];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redraw the graph
|
||||||
historyPlot.setData(convertGraphData(displayedGraphData));
|
historyPlot.setData(convertGraphData(displayedGraphData));
|
||||||
historyPlot.setupGrid();
|
historyPlot.setupGrid();
|
||||||
|
|
||||||
historyPlot.draw();
|
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');
|
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) {
|
function getTimestamp(ms, timeOnly) {
|
||||||
var date = new Date(0);
|
var date = new Date(0);
|
||||||
|
|
||||||
@ -96,7 +120,7 @@ function convertGraphData(rawData) {
|
|||||||
function stringToColor(base) {
|
function stringToColor(base) {
|
||||||
var hash;
|
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);
|
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 config = require('../config.json');
|
||||||
var servers = require('../servers.json');
|
var servers = require('../servers.json');
|
||||||
|
|
||||||
// Checks if we have a server in config.json with the IP.
|
var serverNameLookup = {};
|
||||||
function serverWithIpExists(ip) {
|
|
||||||
|
// 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++) {
|
for (var i = 0; i < servers.length; i++) {
|
||||||
var entry = servers[i];
|
var entry = servers[i];
|
||||||
|
|
||||||
if (entry.ip === ip) {
|
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.
|
// This method is a monstrosity.
|
||||||
@ -20,16 +42,7 @@ function serverWithIpExists(ip) {
|
|||||||
function trimUselessPings(data) {
|
function trimUselessPings(data) {
|
||||||
var keys = Object.keys(data);
|
var keys = Object.keys(data);
|
||||||
|
|
||||||
var keysToRemove = [];
|
|
||||||
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
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 listing = data[keys[i]];
|
||||||
var lastTimestamp = 0;
|
var lastTimestamp = 0;
|
||||||
|
|
||||||
@ -55,11 +68,6 @@ function trimUselessPings(data) {
|
|||||||
|
|
||||||
data[keys[i]] = filteredListing;
|
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) {
|
exports.trimOldPings = function(data) {
|
||||||
@ -98,16 +106,25 @@ exports.setIntervalNoDelay = function(func, delay) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.convertPingsToGraph = function(sqlData) {
|
exports.convertPingsToGraph = function(sqlData) {
|
||||||
|
var serverIps = getServerIps();
|
||||||
var graphData = {};
|
var graphData = {};
|
||||||
|
|
||||||
|
var startTime = exports.getCurrentTimeMs();
|
||||||
|
|
||||||
for (var i = 0; i < sqlData.length; i++) {
|
for (var i = 0; i < sqlData.length; i++) {
|
||||||
var entry = sqlData[i];
|
var entry = sqlData[i];
|
||||||
|
|
||||||
if (!graphData[entry.ip]) {
|
if (serverIps.indexOf(entry.ip) === -1) {
|
||||||
graphData[entry.ip] = [];
|
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.
|
// Break it into minutes.
|
||||||
@ -116,5 +133,7 @@ exports.convertPingsToGraph = function(sqlData) {
|
|||||||
// Drop old data.
|
// Drop old data.
|
||||||
exports.trimOldPings(graphData);
|
exports.trimOldPings(graphData);
|
||||||
|
|
||||||
|
logger.info('Converted data structure in ' + (exports.getCurrentTimeMs() - startTime) + 'ms');
|
||||||
|
|
||||||
return graphData;
|
return graphData;
|
||||||
};
|
};
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "minetrack",
|
"name": "minetrack",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"description": "A Minecraft server tracker that lets you focus on the basics.",
|
"description": "A Minecraft server tracker that lets you focus on the basics.",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
Loading…
Reference in New Issue
Block a user