2015-11-02 04:56:08 +00:00
var server = require ( './lib/server' ) ;
var ping = require ( './lib/ping' ) ;
2015-11-02 05:46:24 +00:00
var logger = require ( './lib/logger' ) ;
2015-11-03 04:32:54 +00:00
var mojang = require ( './lib/mojang_services' ) ;
2015-11-09 00:34:17 +00:00
var util = require ( './lib/util' ) ;
2015-12-11 04:06:27 +00:00
var db = require ( './lib/database' ) ;
2015-11-02 05:46:24 +00:00
2015-11-02 04:56:08 +00:00
var config = require ( './config.json' ) ;
var networkHistory = [ ] ;
var connectedClients = 0 ;
2015-12-18 07:45:38 +00:00
var graphData = [ ] ;
var lastGraphPush = [ ] ;
2015-11-02 06:57:30 +00:00
function pingAll ( ) {
2015-11-02 05:21:42 +00:00
var servers = config . servers ;
2015-11-02 04:56:08 +00:00
2015-11-02 05:21:42 +00:00
for ( var i = 0 ; i < servers . length ; i ++ ) {
2015-11-02 04:56:08 +00:00
// Make sure we lock our scope.
( function ( network ) {
2015-11-03 04:32:54 +00:00
ping . ping ( network . ip , network . port , network . type , config . rates . connectTimeout , function ( err , res ) {
2015-11-02 04:56:08 +00:00
// Handle our ping results, if it succeeded.
if ( err ) {
2015-11-03 04:32:54 +00:00
logger . log ( 'error' , 'Failed to ping ' + network . ip + ': ' + JSON . stringify ( err ) ) ;
2015-11-02 04:56:08 +00:00
}
2015-11-09 01:08:31 +00:00
// If we have favicon override specified, use it.
if ( res && config . faviconOverride && config . faviconOverride [ network . name ] ) {
res . favicon = config . faviconOverride [ network . name ] ;
}
2015-11-24 06:34:00 +00:00
var networkSnapshot = {
info : {
name : network . name ,
timestamp : util . getCurrentTimeMs ( )
}
} ;
2015-11-24 23:24:17 +00:00
if ( res ) {
networkSnapshot . result = res ;
2015-11-24 06:34:00 +00:00
} else if ( err ) {
2015-11-24 23:24:17 +00:00
networkSnapshot . error = err ;
2015-11-24 06:34:00 +00:00
}
server . io . sockets . emit ( 'update' , networkSnapshot ) ;
2015-11-02 05:19:27 +00:00
2015-11-02 04:56:08 +00:00
// Log our response.
2015-11-25 22:40:13 +00:00
if ( ! networkHistory [ network . name ] ) {
networkHistory [ network . name ] = [ ] ;
2015-11-02 04:56:08 +00:00
}
2015-11-25 22:40:13 +00:00
var _networkHistory = networkHistory [ network . name ] ;
2015-11-02 04:56:08 +00:00
2015-11-09 00:34:17 +00:00
// Remove our previous data that we don't need anymore.
2015-11-02 04:56:08 +00:00
for ( var i = 0 ; i < _networkHistory . length ; i ++ ) {
2015-11-09 00:34:17 +00:00
delete _networkHistory [ i ] . info ;
2015-11-24 06:34:00 +00:00
if ( _networkHistory [ i ] . result ) {
delete _networkHistory [ i ] . result . favicon ;
}
2015-11-02 04:56:08 +00:00
}
_networkHistory . push ( {
2015-11-02 06:57:30 +00:00
error : err ,
2015-11-09 00:34:17 +00:00
result : res ,
timestamp : util . getCurrentTimeMs ( ) ,
info : {
ip : network . ip ,
port : network . port ,
type : network . type ,
name : network . name
}
2015-11-02 04:56:08 +00:00
} ) ;
// Make sure we never log too much.
2015-11-09 00:34:17 +00:00
if ( _networkHistory . length > 72 ) { // 60/2.5 = 24, so 24 is one minute
2015-11-02 04:56:08 +00:00
_networkHistory . shift ( ) ;
}
2015-12-11 04:06:27 +00:00
// Log it to the database if needed.
if ( config . logToDatabase ) {
db . log ( network . ip , util . getCurrentTimeMs ( ) , res ? res . players . online : 0 ) ;
}
2015-12-18 07:45:38 +00:00
// Push it to our graphs.
var timeMs = util . getCurrentTimeMs ( ) ;
2015-12-18 08:17:39 +00:00
// The same mechanic from trimUselessPings is seen here.
// If we dropped the ping, then to avoid destroying the graph, ignore it.
// However if it's been too long since the last successful ping, we'll send it anyways.
if ( ! lastGraphPush [ network . ip ] || ( timeMs - lastGraphPush [ network . ip ] >= 60 * 1000 && res ) || timeMs - lastGraphPush [ network . ip ] >= 70 * 1000 ) {
2015-12-18 07:45:38 +00:00
lastGraphPush [ network . ip ] = timeMs ;
// Don't have too much data!
if ( graphData [ network . ip ] . length >= 24 * 60 ) {
graphData [ network . ip ] . shift ( ) ;
}
graphData [ network . ip ] . push ( [ timeMs , res ? res . players . online : 0 ] ) ;
// Send the update.
server . io . sockets . emit ( 'updateHistoryGraph' , {
ip : network . ip ,
players : ( res ? res . players . online : 0 ) ,
timestamp : timeMs
} ) ;
}
2015-11-02 04:56:08 +00:00
} ) ;
2015-11-02 05:21:42 +00:00
} ) ( servers [ i ] ) ;
2015-11-02 04:56:08 +00:00
}
2015-11-02 06:57:30 +00:00
}
2015-11-02 04:56:08 +00:00
2015-11-03 04:32:54 +00:00
// Start our main loop that does everything.
function startMainLoop ( ) {
2015-11-24 23:24:17 +00:00
util . setIntervalNoDelay ( pingAll , config . rates . pingAll ) ;
2015-11-03 04:32:54 +00:00
2015-11-24 23:24:17 +00:00
util . setIntervalNoDelay ( function ( ) {
2015-11-03 04:32:54 +00:00
mojang . update ( config . rates . mojangStatusTimeout ) ;
server . io . sockets . emit ( 'updateMojangServices' , mojang . toMessage ( ) ) ;
} , config . rates . upateMojangStatus ) ;
}
2015-12-11 04:06:27 +00:00
if ( config . logToDatabase ) {
// Setup our database.
db . setup ( ) ;
2015-12-18 07:45:38 +00:00
var timestamp = util . getCurrentTimeMs ( ) ;
db . queryPings ( 24 * 60 * 60 * 1000 , function ( data ) {
graphData = util . convertPingsToGraph ( data ) ;
logger . log ( 'info' , 'Queried and parsed ping history in %sms' , util . getCurrentTimeMs ( ) - timestamp ) ;
} ) ;
2015-12-11 04:06:27 +00:00
} else {
logger . warn ( 'Database logging is not enabled. You can enable it by setting "logToDatabase" to true in config.json. This requires sqlite3 to be installed.' ) ;
}
2015-11-02 05:19:27 +00:00
server . start ( function ( ) {
2015-11-02 04:56:08 +00:00
// Track how many people are currently connected.
server . io . on ( 'connect' , function ( client ) {
2015-11-09 00:34:17 +00:00
// If we haven't sent out at least one round of pings, disconnect them for now.
2015-11-24 06:26:36 +00:00
if ( Object . keys ( networkHistory ) . length < config . servers . length ) {
2015-11-09 00:34:17 +00:00
client . disconnect ( ) ;
return ;
}
2015-11-02 04:56:08 +00:00
// We're good to connect them!
connectedClients += 1 ;
2015-11-02 05:46:24 +00:00
logger . log ( 'info' , 'Accepted connection: %s, total clients: %d' , client . request . connection . remoteAddress , connectedClients ) ;
2015-11-24 06:26:36 +00:00
setTimeout ( function ( ) {
// Send them our previous data, so they have somewhere to start.
client . emit ( 'updateMojangServices' , mojang . toMessage ( ) ) ;
2015-11-02 04:56:08 +00:00
2015-11-24 06:26:36 +00:00
// Remap our associative array into just an array.
var networkHistoryKeys = Object . keys ( networkHistory ) ;
2015-11-02 04:56:08 +00:00
2015-11-25 22:40:13 +00:00
networkHistoryKeys . sort ( ) ;
2015-11-24 06:26:36 +00:00
// Send each individually, this should look cleaner than waiting for one big array to transfer.
for ( var i = 0 ; i < networkHistoryKeys . length ; i ++ ) {
client . emit ( 'add' , [ networkHistory [ networkHistoryKeys [ i ] ] ] ) ;
}
2015-12-18 07:45:38 +00:00
// Send them the big 24h graph.
client . emit ( 'historyGraph' , graphData ) ;
2015-11-24 06:26:36 +00:00
} , 1 ) ;
2015-11-02 04:56:08 +00:00
// Attach our listeners.
client . on ( 'disconnect' , function ( client ) {
connectedClients -= 1 ;
2015-11-02 06:01:04 +00:00
logger . log ( 'info' , 'Client disconnected, total clients: %d' , connectedClients ) ;
2015-11-02 04:56:08 +00:00
} ) ;
} ) ;
2015-11-02 06:57:30 +00:00
2015-11-03 04:32:54 +00:00
startMainLoop ( ) ;
2015-11-02 04:56:08 +00:00
} ) ;