This commit is contained in:
Cryptkeeper! 2017-03-11 17:44:21 -06:00 committed by GitHub
parent b973968eca
commit 2c4f3e0865
11 changed files with 104 additions and 94 deletions

17
app.js

@ -18,6 +18,7 @@ var currentVersionIndex = {
var networkVersions = []; var networkVersions = [];
var graphData = []; var graphData = [];
var highestPlayerCount = {};
var lastGraphPush = []; var lastGraphPush = [];
function pingAll() { function pingAll() {
@ -91,11 +92,18 @@ function handlePing(network, res, err, attemptedVersion) {
timestamp: util.getCurrentTimeMs(), timestamp: util.getCurrentTimeMs(),
type: network.type type: network.type
}, },
versions: _networkVersions versions: _networkVersions,
record: highestPlayerCount[network.ip]
}; };
if (res) { if (res) {
networkSnapshot.result = res; networkSnapshot.result = res;
// Validate that we have logToDatabase enabled otherwise in memory pings
// will create a record that's only valid for the runtime duration.
if (config.logToDatabase && res.players.online > highestPlayerCount[network.ip]) {
highestPlayerCount[network.ip] = res.players.online;
}
} else if (err) { } else if (err) {
networkSnapshot.error = err; networkSnapshot.error = err;
} }
@ -122,7 +130,7 @@ function handlePing(network, res, err, attemptedVersion) {
ip: network.ip, ip: network.ip,
port: network.port, port: network.port,
type: network.type, type: network.type,
name: network.name, name: network.name
} }
}); });
@ -252,7 +260,10 @@ if (config.logToDatabase) {
var timestamp = util.getCurrentTimeMs(); var timestamp = util.getCurrentTimeMs();
db.queryPings(config.graphDuration, function(data) { db.queryPings(config.graphDuration, function(data) {
graphData = util.convertPingsToGraph(data); var result = util.convertServerHistory(data);
graphData = result.graphData;
highestPlayerCount = result.highestPlayerCount;
logger.log('info', 'Queried and parsed ping history in %sms', util.getCurrentTimeMs() - timestamp); logger.log('info', 'Queried and parsed ping history in %sms', util.getCurrentTimeMs() - timestamp);

@ -6,7 +6,7 @@
} }
body { body {
background: #2E2B2C; background: #212021;
color: #FFF; color: #FFF;
font-family: "Open Sans", sans-serif; font-family: "Open Sans", sans-serif;
font-size: 18px; font-size: 18px;
@ -27,13 +27,18 @@ a {
min-height: 100%; min-height: 100%;
} }
/* Constants */
#header, #footer, #tagline {
width: 1540px;
margin: 0 auto;
}
/* Header */ /* Header */
#header { #header {
background: #EBEBEB; background: #EBEBEB;
color: #3B3738; color: #3B3738;
padding: 20px 0; padding: 20px 0;
overflow: auto; overflow: auto;
margin-top: 44px;
} }
#header .slogan { #header .slogan {
@ -47,8 +52,8 @@ a {
#header a, #footer a { #header a, #footer a {
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
border-bottom: 1px dashed #3B3738; border-bottom: 1px dashed #3B3738;
} }
#header a:hover, #footer a:hover { #header a:hover, #footer a:hover {
border-bottom: 1px dashed transparent; border-bottom: 1px dashed transparent;
@ -66,13 +71,11 @@ a {
/* Footer */ /* Footer */
#footer { #footer {
width: 1540px;
font-size: 16px; font-size: 16px;
text-transform: uppercase; text-transform: uppercase;
background: #EBEBEB; background: #EBEBEB;
color: #3B3738; color: #3B3738;
padding: 15px 0; padding: 15px 0;
margin: 0 auto;
border-top-right-radius: 2px; border-top-right-radius: 2px;
border-top-left-radius: 2px; border-top-left-radius: 2px;
text-align: center; text-align: center;
@ -81,16 +84,9 @@ a {
/* Tagline */ /* Tagline */
#tagline { #tagline {
padding: 10px 0; padding: 10px 0;
width: 100%; text-align: center;
z-index: 999999; /* I'm so sorry. */ border-bottom-right-radius: 2px;
position: fixed; border-bottom-left-radius: 2px;
left: 0;
top: 0;
}
#tagline-center {
width: 1520px;
margin: 0 auto;
} }
/* Colors used by the Mojang service's status bar */ /* Colors used by the Mojang service's status bar */
@ -142,10 +138,6 @@ a {
padding-top: 4px; padding-top: 4px;
} }
.server > .column > .url {
font-size: 16px;
}
.server > .column > h3 > .type { .server > .column > h3 > .type {
padding: 1px 5px; padding: 1px 5px;
border-radius: 2px; border-radius: 2px;
@ -154,16 +146,8 @@ a {
margin-bottom: 2px; margin-bottom: 2px;
} }
.server > .column > .versions {
min-height: 23px;
padding-bottom: 1px;
}
.server > .column > .versions > .version { .server > .column > .versions > .version {
padding: 1px 5px; font-size: 16px;
border-radius: 2px;
border: 1px solid #636363;
font-size: 12px;
} }
.category-header { .category-header {
@ -256,4 +240,5 @@ h3 {
.button:hover { .button:hover {
background: #ecf0f1; background: #ecf0f1;
color: #3498db; color: #3498db;
cursor: pointer;
} }

@ -18,29 +18,25 @@
<div id="push"> <div id="push">
<div id="tagline" class="status-connecting">
<div id="tagline-center">
<span id="tagline-text" class="text-uppercase">Connecting...</span>
</div>
</div>
<div id="header"> <div id="header">
<div id="column-center"> <div id="column-center">
<img src="/images/compass.png" width="28" height="28" style="display: inline-block; margin-right: 5px;"> <img src="/images/compass.png" width="28" height="28" style="display: inline-block; margin-right: 5px;">
<h1 style="display: inline-block;" class="text-uppercase">Minetrack</h1> <h1 style="display: inline-block;" class="text-uppercase">Minetrack</h1>
<p class="subslogan text-uppercase">Watching <span id="stat_totalPlayers">0</span> players on <span id="stat_networks">0</span> networks.</p> <p class="subslogan text-uppercase">Watching <span id="stat_totalPlayers">0</span> players on <span id="stat_networks">0</span> networks.</p>
</div> </div>
</div> </div>
<div id="tagline" class="status-connecting">
<span id="tagline-text" class="text-uppercase">Connecting...</span>
</div>
<div id="big-graph"></div> <div id="big-graph"></div>
<div id="big-graph-controls" style="display: none;"> <div id="big-graph-controls" style="display: none;">
@ -50,7 +46,7 @@
<a onclick="toggleControlsDrawer();">Click to toggle graph controls</a> <a onclick="toggleControlsDrawer();">Click to toggle graph controls</a>
</span> </span>
<div id="big-graph-controls-drawer" style="display: none;"> <div id="big-graph-controls-drawer" style="display: none;">
<div id="big-graph-checkboxes"></div> <div id="big-graph-checkboxes"></div>
@ -74,19 +70,14 @@
<div id="footer"> <div id="footer">
<p> Made with <span style="color: #e74c3c;">&#9829;</span> by <a href="http://cryptkpr.me">Cryptkeeper</a>. Read the source code on <a href="https://github.com/Cryptkeeper/Minetrack">Github</a>.<br />
*Older records may not be reflected due to tracking behavior.
Made with <span style="color: #e74c3c;">&#9829;</span> by <a href="http://cryptkpr.me">Cryptkeeper</a> &middot; Source code available on <a href="https://github.com/Cryptkeeper/Minetrack">Github</a>
</p>
</div> </div>
<!-- External JS assets --> <!-- External JS assets -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.7/socket.io.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.7/socket.io.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.min.js"></script>
<!-- Internal JS assets --> <!-- Internal JS assets -->

@ -5,17 +5,6 @@ var historyPlot;
var displayedGraphData; var displayedGraphData;
var hiddenGraphData = []; var hiddenGraphData = [];
var mcVersions = {
'PC': {
4: '1.7.2',
5: '1.7.10',
47: '1.8',
107: '1.9',
210: '1.10',
315: '1.11'
}
};
var isConnected = false; var isConnected = false;
var mojangServicesUpdater; var mojangServicesUpdater;
@ -31,7 +20,7 @@ function updateServerStatus(lastEntry) {
var versions = ''; var versions = '';
for (var i = 0; i < lastEntry.versions.length; i++) { for (var i = 0; i < lastEntry.versions.length; i++) {
versions += '<span class="version">' + mcVersions[lastEntry.info.type][lastEntry.versions[i]] + '</span>&nbsp;'; versions += '<span class="version">' + publicConfig.minecraftVersions[lastEntry.info.type][lastEntry.versions[i]] + '</span>&nbsp;';
} }
versionDiv.html(versions); versionDiv.html(versions);
@ -81,6 +70,10 @@ function updateServerStatus(lastEntry) {
$("#stat_totalPlayers").text(formatNumber(totalPlayers)); $("#stat_totalPlayers").text(formatNumber(totalPlayers));
$("#stat_networks").text(formatNumber(keys.length)); $("#stat_networks").text(formatNumber(keys.length));
if (lastEntry.record) {
$('#record_' + safeName(info.name)).html('Record: ' + formatNumber(lastEntry.record));
}
} }
function sortServers() { function sortServers() {
@ -220,7 +213,7 @@ $(document).ready(function() {
socket.on('disconnect', function() { socket.on('disconnect', function() {
if (mojangServicesUpdater) clearInterval(mojangServicesUpdater); if (mojangServicesUpdater) clearInterval(mojangServicesUpdater);
if (sortServersTask) clearInterval(sortServersTask); if (sortServersTask) clearInterval(sortServersTask);
lastMojangServiceUpdate = undefined; lastMojangServiceUpdate = undefined;
$('#tagline').attr('class', 'status-offline'); $('#tagline').attr('class', 'status-offline');
@ -346,22 +339,26 @@ $(document).ready(function() {
lastPlayerEntries[info.name] = lastEntry.result.players.online; lastPlayerEntries[info.name] = lastEntry.result.players.online;
} }
var typeString = publicConfig.serverTypesVisible ? '<span class="type">' + info.type + '</span>' : '';
var safeNameCopy = safeName(info.name);
$('<div/>', { $('<div/>', {
id: safeName(info.name), id: safeNameCopy,
class: 'server', class: 'server',
html: '<div id="server-' + safeName(info.name) + '" class="column" style="width: 80px;">\ html: '<div id="server-' + safeNameCopy + '" class="column" style="width: 80px;">\
<img id="favicon_' + safeName(info.name) + '">\ <img id="favicon_' + safeNameCopy + '" title="' + info.ip + printPort(info.port) + '">\
<br />\ <br />\
<p class="text-center-align rank" id="ranking_' + safeName(info.name) + '"></p>\ <p class="text-center-align rank" id="ranking_' + safeNameCopy + '"></p>\
</div>\ </div>\
<div class="column" style="width: 220px;">\ <div class="column" style="width: 220px;">\
<h3>' + info.name + '&nbsp;<span class="type">' + info.type + '</span></h3>\ <h3>' + info.name + '&nbsp;' + typeString + '</h3>\
<span class="color-gray url">' + info.ip + printPort(info.port) + '</span>\ <span id="status_' + safeNameCopy + '">Waiting</span>\
<div id="version_' + safeName(info.name) + '" class="versions"><span class="version"></span></div>\ <div id="version_' + safeNameCopy + '" class="color-gray versions"><span class="version"></span></div>\
<span id="status_' + safeName(info.name) + '">Waiting</span>\ <span id="record_' + safeNameCopy + '" class="color-gray"></span>\
</div>\ </div>\
<div class="column" style="float: right;">\ <div class="column" style="float: right;">\
<div class="chart" id="chart_' + safeName(info.name) + '"></div>\ <div class="chart" id="chart_' + safeNameCopy + '"></div>\
</div>' </div>'
}).appendTo("#server-container-" + getServerByIp(info.ip).category); }).appendTo("#server-container-" + getServerByIp(info.ip).category);
@ -375,12 +372,12 @@ $(document).ready(function() {
graphs[lastEntry.info.name] = { graphs[lastEntry.info.name] = {
listing: listing, listing: listing,
plot: $.plot('#chart_' + safeName(info.name), [listing], smallChartOptions) plot: $.plot('#chart_' + safeNameCopy, [listing], smallChartOptions)
}; };
updateServerStatus(lastEntry); updateServerStatus(lastEntry);
$('#chart_' + safeName(info.name)).bind('plothover', handlePlotHover); $('#chart_' + safeNameCopy).bind('plothover', handlePlotHover);
} }
sortServers(); sortServers();

@ -109,7 +109,8 @@ function updateMojangServices(currentUpdate) {
var entry = lastMojangServiceUpdate[keys[i]]; var entry = lastMojangServiceUpdate[keys[i]];
if (entry.startTime) { if (entry.startTime) {
newStatus += entry.name + ' ' + entry.title.toLowerCase() + ' for ' + msToTime((new Date()).getTime() - entry.startTime + ' '); newStatus += entry.name + ' ' + entry.title.toLowerCase() + ' for ' + msToTime((new Date()).getTime() - entry.startTime);
if (i < keys.length - 1) newStatus += ', ';
} }
} }
} }
@ -218,4 +219,4 @@ function msToTime(timer) {
} }
return string; return string;
} }

@ -8,7 +8,7 @@
"/css/main.css": "assets/css/main.css" "/css/main.css": "assets/css/main.css"
}, },
"faviconOverride": { "faviconOverride": {
}, },
"site": { "site": {
"port": 8080, "port": 8080,
@ -39,5 +39,6 @@
0 0
] ]
}, },
"categoriesVisible": true "categoriesVisible": true,
"serverTypesVisible": true
} }

@ -1,3 +1,10 @@
**3.0.0** *(Mar 11 2017)*
- Adds player count records.
- Adds "serverTypesVisible" to hide PC/PE badges.
- Moves Minecraft protocol versions out of site.js and into minecraft.json.
- Design tweaks to remove fluff.
- Fixes various bugs.
**2.2.2** *(Jul 5 2016)* **2.2.2** *(Jul 5 2016)*
- Now builds against mcpe-ping-fixed (requires a ```npm install```)! - Now builds against mcpe-ping-fixed (requires a ```npm install```)!

@ -8,6 +8,7 @@ var util = require('./util');
var logger = require('./logger'); var logger = require('./logger');
var config = require('../config.json'); var config = require('../config.json');
var minecraft = require('../minecraft.json');
var servers = require('../servers.json'); var servers = require('../servers.json');
var urlMapping = []; var urlMapping = [];
@ -68,7 +69,9 @@ function handleRequest(req, res) {
graphDuration: config.graphDuration, graphDuration: config.graphDuration,
servers: servers, servers: servers,
bootTime: util.getBootTime(), bootTime: util.getBootTime(),
categoriesVisible: config.categoriesVisible || false categoriesVisible: config.categoriesVisible || false,
serverTypesVisible: config.serverTypesVisible || false,
minecraftVersions: minecraft.versions
}; };
res.write('setPublicConfig(' + JSON.stringify(publicConfig) + ');'); res.write('setPublicConfig(' + JSON.stringify(publicConfig) + ');');
@ -78,7 +81,7 @@ function handleRequest(req, res) {
var file = urlMapping[requestUrl]; var file = urlMapping[requestUrl];
res.setHeader('Content-Type', mime.lookup(file)); res.setHeader('Content-Type', mime.lookup(file));
fs.createReadStream(file).pipe(res); fs.createReadStream(file).pipe(res);
} else { } else {
res.statusCode = 404; res.statusCode = 404;
@ -102,4 +105,4 @@ exports.start = function() {
// Since everything is loaded, let's celebrate! // Since everything is loaded, let's celebrate!
logger.log('info', 'Started on %s:%d', config.site.ip, config.site.port); logger.log('info', 'Started on %s:%d', config.site.ip, config.site.port);
}; };

@ -108,26 +108,25 @@ exports.setIntervalNoDelay = function(func, delay) {
return task; return task;
}; };
exports.convertPingsToGraph = function(sqlData) { exports.convertServerHistory = function(sqlData) {
var serverIps = getServerIps(); var serverIps = getServerIps();
var graphData = {}; var graphData = {};
var highestPlayerCount = {};
var startTime = exports.getCurrentTimeMs(); 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 (serverIps.indexOf(entry.ip) === -1) { if (serverIps.indexOf(entry.ip) === -1) continue;
continue;
}
var name = getServerNameByIp(entry.ip); var name = getServerNameByIp(entry.ip);
if (!graphData[name]) { if (!graphData[name]) graphData[name] = [];
graphData[name] = [];
}
graphData[name].push([entry.timestamp, entry.playerCount]); graphData[name].push([entry.timestamp, entry.playerCount]);
if (!highestPlayerCount[entry.ip]) highestPlayerCount[entry.ip] = 0;
if (entry.playerCount > highestPlayerCount[entry.ip]) highestPlayerCount[entry.ip] = entry.playerCount;
} }
// Break it into minutes. // Break it into minutes.
@ -136,9 +135,12 @@ 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'); logger.info('Parsed ' + sqlData.length + ' ping records in ' + (exports.getCurrentTimeMs() - startTime) + 'ms');
return graphData; return {
graphData: graphData,
highestPlayerCount: highestPlayerCount
};
}; };
exports.getBootTime = function() { exports.getBootTime = function() {
@ -166,4 +168,4 @@ exports.unfurlSRV = function(hostname, port, callback) {
} }
callback(records[0].name, records[0].port); callback(records[0].name, records[0].port);
}) })
}; };

12
minecraft.json Normal file

@ -0,0 +1,12 @@
{
"versions": {
"PC": {
"4": "1.7.2",
"5": "1.7.10",
"47": "1.8",
"107": "1.9",
"210": "1.10",
"315": "1.11"
}
}
}

@ -1,6 +1,6 @@
{ {
"name": "minetrack", "name": "minetrack",
"version": "2.2.2", "version": "3.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": {