From 714daace1886584a87aa1e543d0595e98b369a67 Mon Sep 17 00:00:00 2001 From: Daniel Scalzi <d_scalzi@yahoo.com> Date: Sun, 15 Apr 2018 22:35:14 -0400 Subject: [PATCH] Added server status retrieval and implemented it on UI. The player count on the landing page is now functional. If the server cannot be reached, the label and value will change to SERVER and OFFLINE, respectively. This behavior can be modified. --- app/assets/js/actionbinder.js | 30 ++++++++++++++++ app/assets/js/assetguard.js | 4 +-- app/assets/js/preloader.js | 2 +- app/assets/js/serverstatus.js | 65 +++++++++++++++++++++++++++++++++++ app/landing.ejs | 2 +- 5 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 app/assets/js/serverstatus.js diff --git a/app/assets/js/actionbinder.js b/app/assets/js/actionbinder.js index ea67a990..b0c0f38c 100644 --- a/app/assets/js/actionbinder.js +++ b/app/assets/js/actionbinder.js @@ -6,8 +6,11 @@ const ConfigManager = require(path.join(__dirname, 'assets', 'js', 'configmanage const DiscordWrapper = require(path.join(__dirname, 'assets', 'js', 'discordwrapper.js')) const Mojang = require(path.join(__dirname, 'assets', 'js', 'mojang.js')) const AuthManager = require(path.join(__dirname, 'assets', 'js', 'authmanager.js')) +const ServerStatus = require(path.join(__dirname, 'assets', 'js', 'serverstatus.js')) +const {URL} = require('url') let mojangStatusListener +let serverStatusListener // Launch Elements let launch_content, launch_details, launch_progress, launch_progress_label, launch_details_text @@ -86,9 +89,36 @@ document.addEventListener('readystatechange', function(){ document.getElementById('mojang_status_icon').style.color = Mojang.statusToHex(status) } + const refreshServerStatus = async function(){ + console.log('Refreshing Server Status') + const serv = AssetGuard.resolveSelectedServer(ConfigManager.getGameDirectory()) + + let pLabel = 'SERVER' + let pVal = 'OFFLINE' + + try { + console.log(serv) + const serverURL = new URL('my://' + serv.server_ip) + const servStat = await ServerStatus.getStatus(serverURL.hostname, serverURL.port) + if(servStat.online){ + pLabel = 'PLAYERS' + pVal = servStat.onlinePlayers + '/' + servStat.maxPlayers + } + + } catch (err) { + console.warn('Unable to refresh server status, assuming offline.') + console.debug(err) + } + document.getElementById('landingPlayerLabel').innerHTML = pLabel + document.getElementById('player_count').innerHTML = pVal + } + refreshMojangStatuses() + refreshServerStatus() + // Set refresh rate to once every 5 minutes. mojangStatusListener = setInterval(refreshMojangStatuses, 300000) + serverStatusListener = setInterval(refreshServerStatus, 300000) } }, false) diff --git a/app/assets/js/assetguard.js b/app/assets/js/assetguard.js index 1c019565..4b3f0a11 100644 --- a/app/assets/js/assetguard.js +++ b/app/assets/js/assetguard.js @@ -421,11 +421,11 @@ class AssetGuard extends EventEmitter { const servers = distro.servers for(let i=0; i<servers.length; i++){ if(servers[i].default_selected){ - return servers[i].id + return servers[i] } } // If no server declares default_selected, default to the first one declared. - return (servers.length > 0) ? servers[0].id : null + return (servers.length > 0) ? servers[0] : null } /** diff --git a/app/assets/js/preloader.js b/app/assets/js/preloader.js index 6cd68bee..35294758 100644 --- a/app/assets/js/preloader.js +++ b/app/assets/js/preloader.js @@ -15,7 +15,7 @@ AssetGuard.retrieveDistributionDataSync(ConfigManager.getGameDirectory(), false) // Resolve the selected server if its value has yet to be set. if(ConfigManager.getSelectedServer() == null){ console.log('Determining default selected server..') - ConfigManager.setSelectedServer(AssetGuard.resolveSelectedServer(ConfigManager.getGameDirectory())) + ConfigManager.setSelectedServer(AssetGuard.resolveSelectedServer(ConfigManager.getGameDirectory()).id) ConfigManager.save() } diff --git a/app/assets/js/serverstatus.js b/app/assets/js/serverstatus.js new file mode 100644 index 00000000..8e701ac1 --- /dev/null +++ b/app/assets/js/serverstatus.js @@ -0,0 +1,65 @@ +const net = require('net') + +/** + * Retrieves the status of a minecraft server. + * + * @param {string} address The server address. + * @param {number} port Optional. The port of the server. Defaults to 25565. + * @returns {Promise.<Object>} A promise which resolves to an object containing + * status information. + */ +exports.getStatus = function(address, port = 25565){ + + if(port == null || port == ''){ + port = 25565 + } + if(typeof port === 'string'){ + port = parseInt(port) + } + + return new Promise((resolve, reject) => { + const socket = net.connect(port, address, () => { + let buff = new Buffer([0xFE, 0x01]) + socket.write(buff) + }) + + socket.setTimeout(2500, () => { + socket.end() + reject({ + code: 'ETIMEDOUT', + errno: 'ETIMEDOUT', + address, + port + }) + }) + + socket.on('data', (data) => { + if(data != null && data != ''){ + let server_info = data.toString().split('\x00\x00\x00') + const NUM_FIELDS = 6 + if(server_info != null && server_info.length >= NUM_FIELDS){ + resolve({ + online: true, + version: server_info[2].replace(/\u0000/g, ''), + motd: server_info[3].replace(/\u0000/g, ''), + onlinePlayers: server_info[4].replace(/\u0000/g, ''), + maxPlayers: server_info[5].replace(/\u0000/g,'') + }) + } else { + resolve({ + online: false + }) + } + } + socket.end() + }) + + socket.on('error', (err) => { + socket.destroy() + reject(err) + // ENOTFOUND = Unable to resolve. + // ECONNREFUSED = Unable to connect to port. + }) + }) + +} \ No newline at end of file diff --git a/app/landing.ejs b/app/landing.ejs index 1316a13f..ffca44de 100644 --- a/app/landing.ejs +++ b/app/landing.ejs @@ -102,7 +102,7 @@ <div id="left"> <div class="bot_wrapper"> <div id="content"> - <span class="bot_label">PLAYERS</span> + <span class="bot_label" id="landingPlayerLabel">PLAYERS</span> <span id="player_count">18/100</span> <div class="bot_divider"></div> <span class="bot_label">MOJANG STATUS</span>