This commit is contained in:
Cryptkeeper! 2017-03-14 17:07:58 -05:00 committed by GitHub
parent f1dfe2e21b
commit ac0ea0d5d7
11 changed files with 146 additions and 126 deletions

23
app.js

@ -15,6 +15,7 @@ var currentVersionIndex = {
'PC': 0,
'PE': 0
};
var networkVersions = [];
var graphData = [];
@ -245,6 +246,8 @@ function startServices() {
client.emit('add', [networkHistory[networkHistoryKeys[i]]]);
}
}
client.emit('syncComplete');
});
});
@ -260,14 +263,26 @@ if (config.logToDatabase) {
var timestamp = util.getCurrentTimeMs();
db.queryPings(config.graphDuration, function(data) {
var result = util.convertServerHistory(data);
graphData = result.graphData;
highestPlayerCount = result.highestPlayerCount;
graphData = util.convertServerHistory(data);
completedQueries = 0;
logger.log('info', 'Queried and parsed ping history in %sms', util.getCurrentTimeMs() - timestamp);
for (var i = 0; i < servers.length; i++) {
(function(server) {
db.getTotalRecord(server.ip, function(record) {
logger.log('info', 'Completed query for %s', server.ip);
highestPlayerCount[server.ip] = record;
completedQueries += 1;
if (completedQueries === servers.length) {
startServices();
}
});
})(servers[i]);
}
});
} else {
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.');

@ -29,8 +29,7 @@ a {
/* Constants */
#header, #footer, #tagline {
width: 1540px;
margin: 0 auto;
}
/* Header */
@ -40,6 +39,11 @@ a {
overflow: auto;
}
#header-wrapper {
overflow: auto;
min-width: 850px;
}
#header .column {
display: inline-block;
float: left;
@ -63,7 +67,7 @@ a {
text-decoration: none;
color: inherit;
border-bottom: 1px dashed #3B3738;
}
}
#header a:hover, #footer a:hover {
border-bottom: 1px dashed transparent;
@ -81,57 +85,42 @@ a {
/* Footer */
#footer {
font-size: 16px;
font-size: 14px;
text-transform: uppercase;
background: #EBEBEB;
color: #3B3738;
padding: 15px 0;
border-top-right-radius: 2px;
border-top-left-radius: 2px;
min-width: 950px;
margin-top: 15px;
}
/* Tagline */
#tagline {
padding: 10px 0;
#tagline-text {
padding-top: 20px;
text-align: center;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 2px;
}
/* Colors used by the Mojang service's status bar */
.status-online {
background: #87D37C;
color: #3B3738;
}
.status-unstable {
background: #E9E581;
color: #3B3738;
}
.status-offline {
background: #e74c3c;
}
.status-connecting {
background: #3498db;
}
/* Server listing */
.server-container {
width: 1540px;
margin: 10px auto;
overflow: auto;
display: flex; flex-wrap: wrap; justify-content: center;
}
.server {
overflow: auto;
padding: 5px 10px;
margin: 0 5px;
width: 740px;
width: 738px;
border: 1px solid transparent;
display: inline-block;
}
/*.server:hover {
background: #282828;
border: 1px solid #444;
cursor: pointer;
border-radius: 2px;
}*/
.server > .column > img {
border-radius: 2px;
margin-top: 5px;
@ -180,7 +169,7 @@ a {
padding: 5px;
border-radius: 3px;
background: rgba(0, 0, 0, 0.65);
z-index: 999;
z-index: 10000;
}
/* Existing elements */
@ -254,9 +243,7 @@ h3 {
/* Percentage bar */
#perc-bar {
margin-top: 6px;
width: 650px;
height: 50px;
height: 35px;
position: relative;
}
@ -264,10 +251,25 @@ h3 {
height: 100%;
display: inline-block;
position: absolute;
transition: 0.1s all;
}
#perc-bar > .perc-bar-part:hover {
opacity: 0.75;
margin-top: -5px;
transition: 0.2s all;
}
/* Mojang Status */
.mojang-status {
width: 60px;
height: 60px;
display: inline-block;
border-radius: 2px;
text-align: center;
line-height: 20px;
font-size: 12px;
}
.mojang-status > i {
margin-top: 8px;
font-size: 22px;
}

@ -5,6 +5,7 @@
<head>
<link rel="stylesheet" type="text/css" href="css/main.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
<link rel="icon" type="image/png" href="/images/compass.png">
@ -20,6 +21,8 @@
<div id="header">
<div id="header-wrapper">
<div class="column">
<img src="/images/compass.png" width="28" height="28" style="display: inline-block; margin-right: 5px;">
@ -28,20 +31,22 @@
</div>
<div class="column" style="float: right;">
<div id="mojang-status-list" class="column" style="float: right;">
<div class="mojang-status" title="Sessions" id="mojang-status_Sessions"><i class="fa fa-gamepad"></i><br />Sessions</div>
<div class="mojang-status" title="Skins" id="mojang-status_Skins"><i class="fa fa-user"></i><br />Skins</div>
<div class="mojang-status" title="Auth" id="mojang-status_Auth"><i class="fa fa-key"></i><br />Auth</div>
<div class="mojang-status" title="API" id="mojang-status_API"><i class="fa fa-wrench"></i><br />API</div>
</div>
</div>
</div>
<div id="perc-bar"></div>
<div id="perc-bar-text"></div>
</div>
</div>
<div id="tagline" class="status-connecting">
<span id="tagline-text" class="text-uppercase">Connecting...</span>
</div>
<div id="tagline-text">Connecting...</div>
<div id="big-graph"></div>
@ -76,7 +81,7 @@
<div id="footer">
<span style="padding-left: 15px;">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>. Older records may not be reflected due to tracking behavior.</span>
<span style="padding-left: 20px;">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>. Older records may not be reflected due to tracking behavior.</span>
</div>

@ -102,8 +102,7 @@ function sortServers() {
});
for (var x = 0; x < keys.length; x++) {
$('#' + safeName(keys[x])).appendTo('#server-container-' + categories[i]);
$('#container_' + safeName(keys[x])).appendTo('#server-container-' + categories[i]);
$('#ranking_' + safeName(keys[x])).text('#' + (x + 1));
}
}
@ -121,8 +120,7 @@ function sortServers() {
});
for (var i = 0; i < serverNames.length; i++) {
$('#' + safeName(serverNames[i])).appendTo('#server-container-all');
$('#container_' + safeName(serverNames[i])).appendTo('#server-container-all');
$('#ranking_' + safeName(serverNames[i])).text('#' + (i + 1));
}
}
@ -132,7 +130,7 @@ function renderPercentageBarText(server) {
var totalPlayers = getCurrentTotalPlayers();
var playerCount = lastPlayerEntries[server];
$('#perc-bar-text').html('<strong>' + server + '</strong><br />' + roundToPoint(playerCount / totalPlayers * 100, 10) + '% of ' + formatNumber(totalPlayers) + ' tracked players.');
showCaption('<strong>' + server + '</strong>: ' + formatNumber(playerCount) + ' online. <strong>' + roundToPoint(playerCount / totalPlayers * 100, 10) + '%</strong> of ' + formatNumber(totalPlayers) + ' tracked players.');
}
function updatePercentageBar() {
@ -167,17 +165,11 @@ function updatePercentageBar() {
div.mouseover(function(e) {
renderPercentageBarText(server);
var text = $('#perc-bar-text');
text.stop(true, false);
text.slideDown(100);
currentServerHover = server;
});
div.mouseout(function(e) {
$('#perc-bar-text').slideUp(100);
hideCaption();
currentServerHover = undefined;
});
}
@ -187,11 +179,7 @@ function updatePercentageBar() {
div.css({
width: width + 'px',
left: leftPadding + 'px',
'border-top-left-radius': (pos === 0 ? '2px' : 0),
'border-bottom-left-radius': (pos === 0 ? '2px' : 0),
'border-top-right-radius': (pos === keys.length - 1 ? '2px' : 0),
'border-bottom-right-radius': (pos === keys.length ? '2px' : 0)
left: leftPadding + 'px'
});
leftPadding += width;
@ -268,8 +256,7 @@ function validateBootTime(bootTime, socket) {
if (xhr.status === 200) {
validateBootTime(publicConfig.bootTime, socket);
} else {
$('#tagline').attr('class', 'status-offline');
$('#tagline-text').text('Failed to update! Refresh?');
showCaption('Failed to update! Refresh?');
}
});
}
@ -300,8 +287,7 @@ $(document).ready(function() {
lastMojangServiceUpdate = undefined;
$('#tagline').attr('class', 'status-offline');
$('#tagline-text').text('Disconnected! Refresh?');
showCaption('Disconnected! Refresh?');
lastPlayerEntries = {};
graphs = {};
@ -428,10 +414,11 @@ $(document).ready(function() {
var safeNameCopy = safeName(info.name);
$('<div/>', {
id: safeNameCopy,
id: 'container_' + safeNameCopy,
class: 'server',
'server-id': safeNameCopy,
html: '<div id="server-' + safeNameCopy + '" class="column" style="width: 80px;">\
<img id="favicon_' + safeNameCopy + '" title="' + info.ip + printPort(info.port) + '">\
<img id="favicon_' + safeNameCopy + '" title="' + info.name + '\n' + info.ip + printPort(info.port) + '">\
<br />\
<p class="text-center-align rank" id="ranking_' + safeNameCopy + '"></p>\
</div>\
@ -503,6 +490,14 @@ $(document).ready(function() {
}
});
socket.on('syncComplete', function(data) {
$('#tagline-text').slideUp(100);
$(document).on('click', '.server', function(e) {
var serverId = $(this).attr('server-id');
});
});
$(document).on('click', '.graph-control', function(e) {
var serverIp = $(this).attr('data-target-network');
var checked = $(this).attr('checked');
@ -531,4 +526,8 @@ $(document).ready(function() {
saveGraphControls(Object.keys(displayedGraphData));
}
});
$(window).on('resize', function() {
updatePercentageBar();
});
});

@ -8,6 +8,25 @@ var publicConfig;
var createdCategories = false;
var categoriesVisible;
var colorsByStatus = {
'Online': '#87D37C',
'Unstable': '#f1c40f',
'Offline': '#DE5749'
};
function showCaption(html) {
var tagline = $('#tagline-text');
tagline.stop(true, false);
tagline.html(html);
tagline.slideDown(100);
}
function hideCaption() {
var tagline = $('#tagline-text');
tagline.stop(true, false);
tagline.slideUp(100);
}
function setPublicConfig(json) {
publicConfig = json;
@ -80,42 +99,14 @@ function updateMojangServices(currentUpdate) {
}
var keys = Object.keys(lastMojangServiceUpdate);
var newStatus = 'Mojang Services: ';
var serviceCountByType = {
Online: 0,
Unstable: 0,
Offline: 0
};
for (var i = 0; i < keys.length; i++) {
var entry = lastMojangServiceUpdate[keys[i]];
var key = keys[i];
var status = lastMojangServiceUpdate[key];
serviceCountByType[entry.title] += 1;
var div = $('#mojang-status_' + status.name);
div.css({background: colorsByStatus[status.title]});
}
if (serviceCountByType['Online'] === keys.length) {
$('#tagline').attr('class', 'status-online');
newStatus += 'All systems operational.';
} else {
if (serviceCountByType['Unstable'] > serviceCountByType['Offline']) {
$('#tagline').attr('class', 'status-unstable');
} else {
$('#tagline').attr('class', 'status-offline');
}
for (var i = 0; i < keys.length; i++) {
var entry = lastMojangServiceUpdate[keys[i]];
if (entry.startTime) {
newStatus += entry.name + ' ' + entry.title.toLowerCase() + ' for ' + msToTime((new Date()).getTime() - entry.startTime);
if (i < keys.length - 1) newStatus += ', ';
}
}
}
$('#tagline-text').text(newStatus);
}
function findErrorMessage(error) {

@ -1,3 +1,8 @@
**3.1.0** *(Mar 14 2017)*
- Updated design. More flexible!
- Automatically builds indexes on database.
- Fixes issue with record query.
**3.0.0** *(Mar 11 2017)*
- Adds player count records.
- Adds "serverTypesVisible" to hide PC/PE badges.

@ -7,6 +7,8 @@ exports.setup = function() {
db.serialize(function() {
db.run('CREATE TABLE IF NOT EXISTS pings (timestamp BIGINT NOT NULL, ip TINYTEXT, playerCount MEDIUMINT)');
db.run('CREATE INDEX IF NOT EXISTS ip_index ON pings (ip, playerCount)');
db.run('CREATE INDEX IF NOT EXISTS timestamp_index on PINGS (timestamp)');
});
exports.log = function(ip, timestamp, playerCount) {
@ -19,6 +21,14 @@ exports.setup = function() {
insertStatement.finalize();
};
exports.getTotalRecord = function(ip, callback) {
db.all("SELECT MAX(playerCount) FROM pings WHERE ip = ?", [
ip
], function(err, data) {
callback(data[0]['MAX(playerCount)']);
});
};
exports.queryPings = function(duration, callback) {
var currentTime = util.getCurrentTimeMs();

@ -44,7 +44,7 @@ function handleRequest(req, res) {
var categories = config.serverCategories;
// Legacy support for people without categories configured.
if (!categories) {
if (!categories || Object.keys(categories).length === 0) {
categories = {
'default': 'All Networks'
};

@ -111,7 +111,6 @@ exports.setIntervalNoDelay = function(func, delay) {
exports.convertServerHistory = function(sqlData) {
var serverIps = getServerIps();
var graphData = {};
var highestPlayerCount = {};
var startTime = exports.getCurrentTimeMs();
@ -124,9 +123,6 @@ exports.convertServerHistory = function(sqlData) {
if (!graphData[name]) graphData[name] = [];
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.
@ -137,10 +133,7 @@ exports.convertServerHistory = function(sqlData) {
logger.info('Parsed ' + sqlData.length + ' ping records in ' + (exports.getCurrentTimeMs() - startTime) + 'ms');
return {
graphData: graphData,
highestPlayerCount: highestPlayerCount
};
return graphData;
};
exports.getBootTime = function() {

@ -1,6 +1,6 @@
{
"name": "minetrack",
"version": "3.0.0",
"version": "3.1.0",
"description": "A Minecraft server tracker that lets you focus on the basics.",
"main": "app.js",
"dependencies": {