3.1.0 (#69)
This commit is contained in:
parent
f1dfe2e21b
commit
ac0ea0d5d7
25
app.js
25
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);
|
||||
|
||||
startServices();
|
||||
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;
|
||||
@ -62,8 +66,8 @@ a {
|
||||
#header a, #footer a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
border-bottom: 1px dashed #3B3738;
|
||||
}
|
||||
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,28 +21,32 @@
|
||||
|
||||
<div id="header">
|
||||
|
||||
<div class="column">
|
||||
<div id="header-wrapper">
|
||||
|
||||
<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>
|
||||
<p class="subslogan text-uppercase">Watching <span id="stat_totalPlayers">0</span> players on <span id="stat_networks">0</span> networks.</p>
|
||||
<div class="column">
|
||||
|
||||
</div>
|
||||
<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>
|
||||
<p class="subslogan text-uppercase">Watching <span id="stat_totalPlayers">0</span> players on <span id="stat_networks">0</span> networks.</p>
|
||||
|
||||
<div class="column" style="float: right;">
|
||||
</div>
|
||||
|
||||
<div id="perc-bar"></div>
|
||||
<div id="perc-bar-text"></div>
|
||||
<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="tagline" class="status-connecting">
|
||||
<div id="perc-bar"></div>
|
||||
|
||||
<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;">♥</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;">♥</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;
|
||||
|
||||
@ -79,43 +98,15 @@ function updateMojangServices(currentUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
var keys = Object.keys(lastMojangServiceUpdate);
|
||||
var newStatus = 'Mojang Services: ';
|
||||
|
||||
var serviceCountByType = {
|
||||
Online: 0,
|
||||
Unstable: 0,
|
||||
Offline: 0
|
||||
};
|
||||
var keys = Object.keys(lastMojangServiceUpdate);
|
||||
|
||||
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();
|
||||
|
||||
@ -29,4 +39,4 @@ exports.setup = function() {
|
||||
callback(data);
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -77,4 +77,4 @@ exports.update = function(timeout) {
|
||||
exports.toMessage = function() {
|
||||
// This is what we send to the clients.
|
||||
return serviceStates;
|
||||
};
|
||||
};
|
||||
|
@ -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": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user