Configurable rates, handle ping exceptions, Mojang service tracking

This commit is contained in:
Cryptkeeper 2015-11-02 22:32:54 -06:00
parent 72172514b0
commit da5dd8b026
5 changed files with 150 additions and 38 deletions

27
app.js

@ -1,6 +1,7 @@
var server = require('./lib/server'); var server = require('./lib/server');
var ping = require('./lib/ping'); var ping = require('./lib/ping');
var logger = require('./lib/logger'); var logger = require('./lib/logger');
var mojang = require('./lib/mojang_services');
var config = require('./config.json'); var config = require('./config.json');
@ -13,10 +14,10 @@ function pingAll() {
for (var i = 0; i < servers.length; i++) { for (var i = 0; i < servers.length; i++) {
// Make sure we lock our scope. // Make sure we lock our scope.
(function(network) { (function(network) {
ping.ping(network.ip, network.port, network.type, 2500, function(err, res) { ping.ping(network.ip, network.port, network.type, config.rates.connectTimeout, function(err, res) {
// Handle our ping results, if it succeeded. // Handle our ping results, if it succeeded.
if (err) { if (err) {
logger.log('error', 'Failed to ping ' + network.ip + ': ' + err); logger.log('error', 'Failed to ping ' + network.ip + ': ' + JSON.stringify(err));
} }
server.io.sockets.emit('update', res); server.io.sockets.emit('update', res);
@ -47,6 +48,23 @@ function pingAll() {
} }
} }
// Start our main loop that does everything.
function startMainLoop() {
setInterval(pingAll, config.rates.pingAll);
setInterval(function() {
mojang.update(config.rates.mojangStatusTimeout);
server.io.sockets.emit('updateMojangServices', mojang.toMessage());
}, config.rates.upateMojangStatus);
// Manually fire the first round of our tasks.
mojang.update(config.rates.mojangStatusTimeout);
server.io.sockets.emit('updateMojangServices', mojang.toMessage());
pingAll();
}
server.start(function() { server.start(function() {
// Track how many people are currently connected. // Track how many people are currently connected.
server.io.on('connect', function(client) { server.io.on('connect', function(client) {
@ -74,8 +92,5 @@ server.start(function() {
}); });
}); });
// Start our main loop that fires off pings. startMainLoop();
setInterval(pingAll, 2500);
pingAll();
}); });

@ -30,5 +30,11 @@
"site": { "site": {
"port": 80, "port": 80,
"ip": "0.0.0.0" "ip": "0.0.0.0"
},
"rates": {
"upateMojangStatus": 5000,
"mojangStatusTimeout": 3500,
"pingAll": 2500,
"connectTimeout": 2500
} }
} }

80
lib/mojang_services.js Normal file

@ -0,0 +1,80 @@
var request = require('request');
var logger = require('./logger');
var serviceNameLookup = {
'minecraft.net': 'Website',
'sessionserver.mojang.com': 'Sessions',
'authserver.mojang.com': 'Auth',
'textures.minecraft.net': 'Skins',
'api.mojang.com': 'API'
};
var serviceStates = {
// Lazy populated.
};
function updateService(name, status) {
// Only update if we need to.
if (!(name in serviceStates) || serviceStates[name].status !== status) {
var newEntry = {
name: serviceNameLookup[name], // Send the clean name, not the URL.
status: status
};
// If it's an outage, track when it started.
if (status === 'yellow'|| status === 'red') {
newEntry.startTime = (new Date).getTime();
}
// Generate a nice title from the color.
if (status === 'green') {
newEntry.title = 'Online';
} else if (status === 'yellow') {
newEntry.title = 'Unstable';
} else if (status === 'red') {
newEntry.title = 'Offline';
} else {
throw new Error('Unknown Mojang status: ' + status);
}
// Wipe the old status in favor of the new one.
serviceStates[name] = newEntry;
}
}
exports.update = function(timeout) {
request({
uri: 'http://status.mojang.com/check',
method: 'GET',
timeout: timeout
}, function(err, res, body) {
if (err) {
logger.log('error', 'Failed to update Mojang services: %s', JSON.stringify(err));
} else {
try {
body = JSON.parse(body);
for (var i = 0; i < body.length; i++) {
var service = body[i];
var name = Object.keys(service)[0]; // Because they return an array of object, we have to do this :(
// If it's not in the lookup, we don't care about it.
if (name in serviceNameLookup) {
updateService(name, service[name]);
}
}
logger.log('debug', 'Updated Mojang services: %s', JSON.stringify(serviceStates));
} catch(err) {
// Catch anything weird that can happen, since things probably will.
logger.log('error', 'Failed to parse Mojang\'s response: %s', JSON.stringify(err));
}
}
});
};
exports.toMessage = function() {
// This is what we send to the clients.
return serviceStates;
};

@ -5,42 +5,52 @@ var mcpc_ping = require('mc-ping-updated');
function pingMinecraftPC(host, port, timeout, callback) { function pingMinecraftPC(host, port, timeout, callback) {
var milliseconds = (new Date).getTime(); var milliseconds = (new Date).getTime();
mcpc_ping(host, port, function(err, res) { // Try catch incase the down stream module is bad at handling exceptions.
if (err) { try {
callback(err, null); mcpc_ping(host, port, function(err, res) {
} else { if (err) {
// Remap our JSON into our custom structure. callback(err, null);
callback(null, { } else {
players: { // Remap our JSON into our custom structure.
online: res.players.online, callback(null, {
max: res.players.max players: {
}, online: res.players.online,
version: res.version.protocol, max: res.players.max
latency: (new Date).getTime() - milliseconds },
}); version: res.version.protocol,
} latency: (new Date).getTime() - milliseconds
}, timeout); });
}
}, timeout);
} catch (err) {
callback(err, null);
}
} }
// This is a wrapper function for mcpe-ping, mainly used to convert the data structure of the result. // This is a wrapper function for mcpe-ping, mainly used to convert the data structure of the result.
function pingMinecraftPE(host, port, timeout, callback) { function pingMinecraftPE(host, port, timeout, callback) {
var milliseconds = (new Date).getTime(); var milliseconds = (new Date).getTime();
mcpe_ping(host, port || 19132, function(err, res) { // Try catch incase the down stream module is bad at handling exceptions.
if (err) { try {
callback(err, null); mcpe_ping(host, port || 19132, function(err, res) {
} else { if (err) {
// Remap our JSON into our custom structure. callback(err, null);
callback(err, { } else {
players: { // Remap our JSON into our custom structure.
online: res.currentPlayers, callback(err, {
max: res.maxPlayers players: {
}, online: res.currentPlayers,
version: res.version, max: res.maxPlayers
latency: (new Date).getTime() - milliseconds },
}); version: res.version,
} latency: (new Date).getTime() - milliseconds
}, timeout); });
}
}, timeout);
} catch (err) {
callback(err, null);
}
} }
exports.ping = function(host, port, type, timeout, callback) { exports.ping = function(host, port, type, timeout, callback) {

@ -7,6 +7,7 @@
"mc-ping-updated": "0.0.6", "mc-ping-updated": "0.0.6",
"mcpe-ping": "0.0.3", "mcpe-ping": "0.0.3",
"mime": "^1.3.4", "mime": "^1.3.4",
"request": "^2.65.0",
"socket.io": "^1.3.7", "socket.io": "^1.3.7",
"winston": "^2.0.0" "winston": "^2.0.0"
}, },