From 0927bec07047d775127ec55a86fcea35838499dd Mon Sep 17 00:00:00 2001 From: Thomas Deal Date: Sun, 23 Oct 2016 14:43:06 -0400 Subject: [PATCH 1/8] client.js now launches it's own server instance --- .gitignore | 4 +- client.js | 135 ++++++++++++++++++++++++++++++++++--------- config.json | 16 ++--- launchEverything.bat | 5 -- server-settings.json | 23 -------- 5 files changed, 117 insertions(+), 66 deletions(-) delete mode 100644 launchEverything.bat delete mode 100644 server-settings.json diff --git a/.gitignore b/.gitignore index c6f583e4..a9392b83 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ build/Release # Dependency directory # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git node_modules -Factorio* \ No newline at end of file +Factorio* +/factorio +/instances diff --git a/client.js b/client.js index ef59cc74..567c943f 100644 --- a/client.js +++ b/client.js @@ -1,30 +1,111 @@ var fs = require('fs'); var needle = require("needle"); +var child_process = require('child_process'); + // require config.json var config = require('./config'); + +var instance = process.argv[2]; +var instancedirectory = './instances/'+instance; +if (!fs.existsSync(instancedirectory)){ + fs.mkdirSync(instancedirectory); + fs.mkdirSync(instancedirectory + "/script-output/"); + fs.writeFileSync(instancedirectory + "/script-output/output.txt", "") + fs.writeFileSync(instancedirectory + "/script-output/orders.txt", "") + fs.writeFileSync(instancedirectory + "/script-output/txbuffer.txt", ""); + fs.mkdirSync(instancedirectory + "/mods/"); + fs.symlinkSync('../../../clusterio_0.0.3',instancedirectory + "/mods/clusterio_0.0.3",'junction') + fs.writeFileSync(instancedirectory + "/config.ini", "[path]\r\n\ +read-data=__PATH__executable__\\..\\..\\data\r\n\ +write-data=__PATH__executable__\\..\\..\\..\\instances\\"+instance+"\r\n\ +"); + + var instconf = { + "factorioPort": "35001", + "clientPort": "35002", + "clientPassword": "clusterio" + } + fs.writeFileSync(instancedirectory + "/config.json", JSON.stringify(instconf, null, 4)); + + var serversettings = { + "name": config.username +"'s clusterio "+instance, + "description": "", + "tags": ["clusterio"], + "max_players": "20", + "visibility": "lan", + "username": config.username, + "token": config.usertoken, + "game_password": "", + "verify_user_identity": true, + "admins":[config.username], + "allow_commands":"admins-only", + "autosave_interval":10, + "autosave_slots":5, + "afk_autokick_interval":0, + "auto_pause":false + } + fs.writeFileSync(instancedirectory + "/server-settings.json", JSON.stringify(serversettings, null, 4)); + + var createSave = child_process.spawnSync( + './factorio/bin/x64/factorio.exe', + [ + '-c',instancedirectory+'/config.ini', + '--create',instancedirectory+'/save.zip', + ] + ) +} + +var instanceconfig = require(instancedirectory+'/config'); + + +process.on('SIGINT', function() { + console.log("Caught interrupt signal"); + //serverprocess.stdin.write('/quit') +}); + + +//var serverprocess = child_process.exec(commandline) +var serverprocess = child_process.spawn( + './factorio/bin/x64/factorio.exe', + [ + '-c',instancedirectory+'/config.ini', + '--start-server',instancedirectory+'/save.zip', + '--rcon-port',instanceconfig.clientPort, + '--rcon-password',instanceconfig.clientPassword, + '--server-settings',instancedirectory+'/server-settings.json', + '--port',instanceconfig.factorioPort + ], + { + 'stdio':['pipe','pipe','pipe'] + } +) + +serverprocess.on('close', (code) => { + console.log(`child process exited with code ${code}`); + process.exit(); +}); + +serverprocess.stdout.on('data', (chunk) => { + console.log('OUT: '+chunk); +}) + +serverprocess.stderr.on('data', (chunk) => { + console.log('ERR: '+chunk); +}) + // connect us to the server with rcon // IP, port, password var Rcon = require('simple-rcon'); var client = new Rcon({ - host: config.clientIP, - port: config.clientPort, - password: config.clientPassword, + host: 'localhost', + port: instanceconfig.clientPort, + password: instanceconfig.clientPassword, timeout: 0 -}).connect(); +}); -if (!fs.existsSync(config.factorioDirectory)){ - console.error("FATAL ERROR: config.factorioDirectory DOES NOT EXIST, PLEASE UPDATE CONFIG.JSON"); - process.exit(1); -} -// make sure we got the files we need -if (!fs.existsSync(config.factorioDirectory + "/script-output/")){ - fs.mkdirSync(config.factorioDirectory + "/script-output/"); -} -if (!fs.existsSync(config.factorioDirectory + "/script-output/")){ - fs.writeFileSync(config.factorioDirectory + "/script-output/output.txt", "") -} -fs.writeFileSync(config.factorioDirectory + "/script-output/orders.txt", "") -fs.writeFileSync(config.factorioDirectory + "/script-output/txbuffer.txt", ""); +// wait a few seconds to let the server finish starting before connecting rcon +//TODO: catch '2.033 Info RemoteCommandProcessor.cpp:97: Starting RCON interface at port 35002' from stdout maybe? +setTimeout(() => { client.connect(); }, 5000); client.on('authenticated', function() { console.log('Authenticated!'); @@ -41,12 +122,12 @@ confirmedOrders = []; lastSignalCheck = Date.now(); // provide items -------------------------------------------------------------- // trigger when something happens to output.txt -fs.watch(config.factorioDirectory + "/script-output/output.txt", function(eventType, filename) { +fs.watch(instancedirectory + "/script-output/output.txt", function(eventType, filename) { // get array of lines in file - items = fs.readFileSync(config.factorioDirectory + "/script-output/output.txt", "utf8").split("\n"); + items = fs.readFileSync(instancedirectory + "/script-output/output.txt", "utf8").split("\n"); // if you found anything, reset the file if(items[0]) { - fs.writeFileSync(config.factorioDirectory + "/script-output/output.txt", "") + fs.writeFileSync(instancedirectory + "/script-output/output.txt", "") } for(i = 0;i < items.length; i++) { if(items[i]) { @@ -54,7 +135,7 @@ fs.watch(config.factorioDirectory + "/script-output/output.txt", function(eventT g[0] = g[0].replace("\u0000", ""); console.log("exporting " + JSON.stringify(g)); // send our entity and count to the master for him to keep track of - needle.post(config.masterIP + ":" + config.masterPort + '/place', {name:g[0], count:g[1]}, + needle.post(config.masterIP + ":" + config.masterPort + '/place', {name:g[0], count:g[1]}, function(err, resp, body){ // console.log(body); }); @@ -64,10 +145,10 @@ fs.watch(config.factorioDirectory + "/script-output/output.txt", function(eventT // request items -------------------------------------------------------------- setInterval(function() { // get array of lines in file - items = fs.readFileSync(config.factorioDirectory + "/script-output/orders.txt", "utf8").split("\n"); + items = fs.readFileSync(instancedirectory + "/script-output/orders.txt", "utf8").split("\n"); // if we actually got anything from the file, proceed and reset file if(items[0]) { - fs.writeFileSync(config.factorioDirectory + "/script-output/orders.txt", ""); + fs.writeFileSync(instancedirectory + "/script-output/orders.txt", ""); // prepare a package of all our requested items in a more tranfer friendly format var preparedPackage = {}; for(i = 0;i < items.length; i++) { @@ -140,12 +221,12 @@ setInterval(function() { }); // after fetching all the latest frames, we take a timestamp. During the next iteration, we fetch all frames submitted after this. lastSignalCheck = Date.now(); - + // get array of lines in file, each line should correspond to a JSON encoded frame - signals = fs.readFileSync(config.factorioDirectory + "/script-output/txbuffer.txt", "utf8").split("\n"); + signals = fs.readFileSync(instancedirectory + "/script-output/txbuffer.txt", "utf8").split("\n"); // if we actually got anything from the file, proceed and reset file if(signals[0]) { - fs.writeFileSync(config.factorioDirectory + "/script-output/txbuffer.txt", ""); + fs.writeFileSync(instancedirectory + "/script-output/txbuffer.txt", ""); // loop through all our frames for(i = 0;i < signals.length; i++) { (function(i){ @@ -167,4 +248,4 @@ setInterval(function() { })(i); } } -}, 1000) \ No newline at end of file +}, 1000) diff --git a/config.json b/config.json index d3b3df82..8f7beb15 100644 --- a/config.json +++ b/config.json @@ -1,12 +1,8 @@ { - "__comment": "", - "__comment": "IP and port and password the factorio server runs at for rcon connection", - "clientIP": "localhost", - "clientPort": "12345", - "clientPassword": "123", - "__comment": "Where factorio folder. Should be in the same folder as this config file.", - "factorioDirectory": "factorio 0.13.9", - "__comment": "IP the master web server runs at, can be ignored on the master system", + "__comment": "IP and port for the clusterio master", "masterIP": "localhost", - "masterPort": 8080 -} \ No newline at end of file + "masterPort": 8080, + "__comment": "credentials for factorio MP services", + "username": "", + "usertoken": "" +} diff --git a/launchEverything.bat b/launchEverything.bat deleted file mode 100644 index f08a766e..00000000 --- a/launchEverything.bat +++ /dev/null @@ -1,5 +0,0 @@ -cd "Factorio_0.13.17" -@RD /S /Q "temp" -cd "bin/x64/" -start factorio.exe --start-server testmap.zip --rcon-port 12345 --rcon-password 123 --server-settings server-settings.json -pause \ No newline at end of file diff --git a/server-settings.json b/server-settings.json deleted file mode 100644 index 6e6009ff..00000000 --- a/server-settings.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "Name of the game as it will appear in the game listing", - "description": "Description of the game that will appear in the listing", - "tags": ["game", "tags"], - "max_players": "0", - - "_comment_visibility": ["public: Game will be published on the official Factorio matching server", - "lan: Game will be broadcast on LAN", - "hidden: Game will not be published anywhere"], - "visibility": "public", - - "_comment_credentials": "Your factorio.com login credentials. Required for games with visibility public", - "username": "", - "password": "", - - "_comment_token": "Authentication token. May be used instead of 'password' above.", - "token": "", - - "game_password": "", - - "_comment_verify_user_identity": "When set to true, the server will only allow clients that have a valid Factorio.com account", - "verify_user_identity": false -} From 2234d416558db66929b2ba8c4663bda3bf2e8c0a Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Mon, 24 Oct 2016 09:31:30 +0200 Subject: [PATCH 2/8] Housekeeping, more config settings --- client.js | 71 +++++++++++++++++++++++++++----------------------- config.json | 19 +++++++++++--- package.json | 1 + static/main.js | 9 +------ 4 files changed, 55 insertions(+), 45 deletions(-) diff --git a/client.js b/client.js index 567c943f..c8541323 100644 --- a/client.js +++ b/client.js @@ -6,6 +6,10 @@ var child_process = require('child_process'); var config = require('./config'); var instance = process.argv[2]; +if(!instance){ + console.error("Usage: node client.js [instance name]") + process.exit(1) +} var instancedirectory = './instances/'+instance; if (!fs.existsSync(instancedirectory)){ fs.mkdirSync(instancedirectory); @@ -20,39 +24,39 @@ read-data=__PATH__executable__\\..\\..\\data\r\n\ write-data=__PATH__executable__\\..\\..\\..\\instances\\"+instance+"\r\n\ "); - var instconf = { - "factorioPort": "35001", - "clientPort": "35002", - "clientPassword": "clusterio" - } - fs.writeFileSync(instancedirectory + "/config.json", JSON.stringify(instconf, null, 4)); +var instconf = { + "factorioPort": "35001", + "clientPort": "35002", + "clientPassword": "clusterio" +} +fs.writeFileSync(instancedirectory + "/config.json", JSON.stringify(instconf, null, 4)); - var serversettings = { - "name": config.username +"'s clusterio "+instance, - "description": "", - "tags": ["clusterio"], - "max_players": "20", - "visibility": "lan", - "username": config.username, - "token": config.usertoken, - "game_password": "", - "verify_user_identity": true, - "admins":[config.username], - "allow_commands":"admins-only", - "autosave_interval":10, - "autosave_slots":5, - "afk_autokick_interval":0, - "auto_pause":false - } - fs.writeFileSync(instancedirectory + "/server-settings.json", JSON.stringify(serversettings, null, 4)); +var serversettings = { + "name": config.username +"'s clusterio "+instance, + "description": config.description, + "tags": ["clusterio"], + "max_players": "20", + "visibility": "lan", + "username": config.username, + "token": config.usertoken, + "game_password": config.game_password, + "verify_user_identity": config.verify_user_identity, + "admins":[config.username], + "allow_commands":config.allow_commands, + "autosave_interval":10, + "autosave_slots":5, + "afk_autokick_interval":0, + "auto_pause":config.auto_pause +} +fs.writeFileSync(instancedirectory + "/server-settings.json", JSON.stringify(serversettings, null, 4)); - var createSave = child_process.spawnSync( - './factorio/bin/x64/factorio.exe', - [ - '-c',instancedirectory+'/config.ini', - '--create',instancedirectory+'/save.zip', - ] - ) +var createSave = child_process.spawnSync( + './' + config.factorioDirectory + '/bin/x64/factorio.exe', + [ + '-c',instancedirectory+'/config.ini', + '--create',instancedirectory+'/save.zip', + ] +) } var instanceconfig = require(instancedirectory+'/config'); @@ -66,7 +70,7 @@ process.on('SIGINT', function() { //var serverprocess = child_process.exec(commandline) var serverprocess = child_process.spawn( - './factorio/bin/x64/factorio.exe', + './' + config.factorioDirectory + '/bin/x64/factorio.exe', [ '-c',instancedirectory+'/config.ini', '--start-server',instancedirectory+'/save.zip', @@ -221,7 +225,8 @@ setInterval(function() { }); // after fetching all the latest frames, we take a timestamp. During the next iteration, we fetch all frames submitted after this. lastSignalCheck = Date.now(); - + + // get outbound frames from file and send to master // get array of lines in file, each line should correspond to a JSON encoded frame signals = fs.readFileSync(instancedirectory + "/script-output/txbuffer.txt", "utf8").split("\n"); // if we actually got anything from the file, proceed and reset file diff --git a/config.json b/config.json index 8f7beb15..e7996bff 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,19 @@ { - "__comment": "IP and port for the clusterio master", + "__comment": "Where factorio folder. Should be in the same folder as this config file.", + "factorioDirectory": "factorio_0.14.9 + + "__comment": "IP the master web server runs at, can be ignored on the master system", "masterIP": "localhost", "masterPort": 8080, - "__comment": "credentials for factorio MP services", - "username": "", - "usertoken": "" + + "__comment": "credentials for factorio MP services", + "username": "", + "usertoken": "", + + "__comment": "General user settings", + "verify_user_identity": true, + "auto_pause": false, + "allow_commands": "admins-only", + "game_password": "", + "description": "This server runs Clusterio", } diff --git a/package.json b/package.json index 10e2135f..9332a676 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "license": "ISC", "dependencies": { "body-parser": "^1.15.2", + "child_process": "^1.0.2", "express": "^4.14.0", "fs": "0.0.2", "mkdirp": "^0.5.1", diff --git a/static/main.js b/static/main.js index 319db5b2..c2bb3b98 100644 --- a/static/main.js +++ b/static/main.js @@ -183,14 +183,8 @@ setInterval(function() { }, 500) // image data +// key is the name of the item in the database, value is the name of the image on wiki.factorio.com/images/* var imagedata = { - ["raw-wood"]: "Raw-wood", - ["alien-artifact"]: "Alien-artifact", - ["heavy-oil"]: "Heavy-oil", - ["engine-unit"]: "Engine-unit", - ["electric-engine-unit"]: "Electric-engine-unit", - ["flying-robot-frame"]: "Flying-robot-frame", - ["alien-science_pack"]: "Alien-science-pack", ["empty-barrel"]: "Barrel-empty", ["transport-belt"]: "Basic-transport-belt", ["underground-belt"]: "Basic-transport-belt-to-ground", @@ -224,5 +218,4 @@ var imagedata = { ["piercing-shotgun-shells"]: "Piercing-shotgun-shell", ["accumulator"]: "Basic-accumulator", ["beacon"]: "Basic-beacon", - } From 656c05a30b6d42aa719aea35686724c68807ef77 Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Wed, 26 Oct 2016 08:57:50 +0200 Subject: [PATCH 3/8] Changed default config --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index e7996bff..2642001d 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,6 @@ { "__comment": "Where factorio folder. Should be in the same folder as this config file.", - "factorioDirectory": "factorio_0.14.9 + "factorioDirectory": "factorio", "__comment": "IP the master web server runs at, can be ignored on the master system", "masterIP": "localhost", From 64009a7e162aa57eac0fed301a20f65420582f2b Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Wed, 26 Oct 2016 09:05:43 +0200 Subject: [PATCH 4/8] Valid JSON config file --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 2642001d..765b35c7 100644 --- a/config.json +++ b/config.json @@ -15,5 +15,5 @@ "auto_pause": false, "allow_commands": "admins-only", "game_password": "", - "description": "This server runs Clusterio", + "description": "This server runs Clusterio" } From f6de6e026b1d6f049e4a35642197da8b9b0efe6c Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Thu, 27 Oct 2016 09:21:26 +0200 Subject: [PATCH 5/8] Decreased logging, automatic configuring of multiple instances When creating a new instance, it will now generate a random port for the instance, RCON and an RCON password. Current problems are that its not checking of the port is already taken by something else; if it is, the erver either won't start or RCON will fuck up. --- client.js | 78 +++++++++++++++++++++++++++------------------------- package.json | 1 + 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/client.js b/client.js index c8541323..3ce1eb67 100644 --- a/client.js +++ b/client.js @@ -10,53 +10,57 @@ if(!instance){ console.error("Usage: node client.js [instance name]") process.exit(1) } +if(!fs.existsSync("./instances/")){ + fs.mkdirSync("instances"); +} var instancedirectory = './instances/'+instance; if (!fs.existsSync(instancedirectory)){ fs.mkdirSync(instancedirectory); fs.mkdirSync(instancedirectory + "/script-output/"); fs.writeFileSync(instancedirectory + "/script-output/output.txt", "") fs.writeFileSync(instancedirectory + "/script-output/orders.txt", "") - fs.writeFileSync(instancedirectory + "/script-output/txbuffer.txt", ""); - fs.mkdirSync(instancedirectory + "/mods/"); + fs.writeFileSync(instancedirectory + "/script-output/txbuffer.txt", "") + fs.mkdirSync(instancedirectory + "/mods/") fs.symlinkSync('../../../clusterio_0.0.3',instancedirectory + "/mods/clusterio_0.0.3",'junction') fs.writeFileSync(instancedirectory + "/config.ini", "[path]\r\n\ read-data=__PATH__executable__\\..\\..\\data\r\n\ write-data=__PATH__executable__\\..\\..\\..\\instances\\"+instance+"\r\n\ -"); + "); -var instconf = { - "factorioPort": "35001", - "clientPort": "35002", - "clientPassword": "clusterio" -} -fs.writeFileSync(instancedirectory + "/config.json", JSON.stringify(instconf, null, 4)); + var instconf = { + "factorioPort": Math.floor(Math.random()*65535), + "clientPort": Math.floor(Math.random()*65535), + "clientPassword": Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 8), + } + console.log(instconf) + fs.writeFileSync(instancedirectory + "/config.json", JSON.stringify(instconf, null, 4)); -var serversettings = { - "name": config.username +"'s clusterio "+instance, - "description": config.description, - "tags": ["clusterio"], - "max_players": "20", - "visibility": "lan", - "username": config.username, - "token": config.usertoken, - "game_password": config.game_password, - "verify_user_identity": config.verify_user_identity, - "admins":[config.username], - "allow_commands":config.allow_commands, - "autosave_interval":10, - "autosave_slots":5, - "afk_autokick_interval":0, - "auto_pause":config.auto_pause -} -fs.writeFileSync(instancedirectory + "/server-settings.json", JSON.stringify(serversettings, null, 4)); + var serversettings = { + "name": config.username +"'s clusterio "+instance, + "description": config.description, + "tags": ["clusterio"], + "max_players": "20", + "visibility": "lan", + "username": config.username, + "token": config.usertoken, + "game_password": config.game_password, + "verify_user_identity": config.verify_user_identity, + "admins":[config.username], + "allow_commands":config.allow_commands, + "autosave_interval":10, + "autosave_slots":5, + "afk_autokick_interval":0, + "auto_pause":config.auto_pause + } + fs.writeFileSync(instancedirectory + "/server-settings.json", JSON.stringify(serversettings, null, 4)); -var createSave = child_process.spawnSync( - './' + config.factorioDirectory + '/bin/x64/factorio.exe', - [ - '-c',instancedirectory+'/config.ini', - '--create',instancedirectory+'/save.zip', - ] -) + var createSave = child_process.spawnSync( + './' + config.factorioDirectory + '/bin/x64/factorio.exe', + [ + '-c',instancedirectory+'/config.ini', + '--create',instancedirectory+'/save.zip', + ] + ) } var instanceconfig = require(instancedirectory+'/config'); @@ -137,7 +141,7 @@ fs.watch(instancedirectory + "/script-output/output.txt", function(eventType, fi if(items[i]) { g = items[i].split(" "); g[0] = g[0].replace("\u0000", ""); - console.log("exporting " + JSON.stringify(g)); + // console.log("exporting " + JSON.stringify(g)); // send our entity and count to the master for him to keep track of needle.post(config.masterIP + ":" + config.masterPort + '/place', {name:g[0], count:g[1]}, function(err, resp, body){ @@ -184,7 +188,7 @@ setInterval(function() { }); } // if we got some confirmed orders - console.log("Importing " + confirmedOrders.length + " items! " + JSON.stringify(confirmedOrders)); + // console.log("Importing " + confirmedOrders.length + " items! " + JSON.stringify(confirmedOrders)); sadas = JSON.stringify(confirmedOrders) confirmedOrders = []; // send our RCON command with whatever we got @@ -203,7 +207,7 @@ setInterval(function() { for(i = 0;i Date: Thu, 27 Oct 2016 22:41:25 +0200 Subject: [PATCH 6/8] Basic serverside slaveawareness --- client.js | 36 ++++++++++++++++++++++++++++++++++++ master.js | 20 ++++++++++++++++++++ package.json | 1 + 3 files changed, 57 insertions(+) diff --git a/client.js b/client.js index 3ce1eb67..a7c8ee97 100644 --- a/client.js +++ b/client.js @@ -119,6 +119,7 @@ client.on('authenticated', function() { console.log('Authenticated!'); }).on('connected', function() { console.log('Connected!'); + getID(); }).on('disconnected', function() { console.log('Disconnected!'); // now reconnect @@ -128,6 +129,29 @@ client.on('authenticated', function() { // set some globals confirmedOrders = []; lastSignalCheck = Date.now(); + +// world IDs ------------------------------------------------------------------ +function getID() { + var payload = { + time : Date.now(), + rconPort : instanceconfig.clientPort, + rconPassword : instanceconfig.clientPassword, + serverPort : instanceconfig.factorioPort, + unique : instanceconfig.clientPassword.hashCode() + } + require('getmac').getMac(function(err,mac){ + if (err) throw err + payload.mac = mac + console.log(payload) + needle.post(config.masterIP + ":" + config.masterPort + '/getID', payload, function(err, response, body){ + if(response && response.body) { + // In the future we might be interested in whether or not we actually manage to send it, but honestly I don't care. + console.log(response.body) + } + } ); + }) + +} // provide items -------------------------------------------------------------- // trigger when something happens to output.txt fs.watch(instancedirectory + "/script-output/output.txt", function(eventType, filename) { @@ -258,3 +282,15 @@ setInterval(function() { } } }, 1000) + +// simple string hasher +String.prototype.hashCode = function(){ + var hash = 0; + if (this.length == 0) return hash; + for (i = 0; i < this.length; i++) { + char = this.charCodeAt(i); + hash = ((hash<<5)-hash)+char; + hash = hash & hash; // Convert to 32bit integer + } + return hash; +} diff --git a/master.js b/master.js index 47fa55f7..55a86494 100644 --- a/master.js +++ b/master.js @@ -26,6 +26,7 @@ db = {}; db.items = new Datastore({ filename: 'database/items.db', autoload: true }); db.signals = new Datastore({ filename: 'database/signals.db', autoload: true, inMemoryOnly: true}); db.signals.ensureIndex({ fieldName: 'time', expireAfterSeconds: 3600 }, function (err) {}); +// db.slaves = new Datastore({ filename: 'database/slaves.db', autoload: true, inMemoryOnly: false}); db.items.additem = function(object) { db.items.findOne({name:object.name}, function (err, doc) { @@ -42,6 +43,25 @@ db.items.additem = function(object) { } }) } +var slaves = {} +// world ID management +app.post("/getID", function(req,res) { + // request.body should be an object + // {rconPort, rconPassword, serverPort, mac, time} + // time us a unix timestamp we can use to check for how long the server has been unresponsive + // we should save that somewhere and give appropriate response + if(req.body){ + slaves[req.body.unique] = req.body + console.log("Slave: " + req.body.mac + " : " + req.body.serverPort) + } +}); + +// endpoint for getting information about all our slaves +app.get("/slaves", function(req, res) { + res.header("Access-Control-Allow-Origin", "*"); + res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + res.send(slaves) +}); // endpoint to send items to app.post("/place", function(req, res) { diff --git a/package.json b/package.json index 01b32f75..cb9a0d13 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "child_process": "^1.0.2", "express": "^4.14.0", "fs": "0.0.2", + "getmac": "^1.2.1", "mkdirp": "^0.5.1", "nedb": "^1.8.0", "needle": "^1.1.0", From 85274220e736550ae699e2028acd88ad5b61bc9c Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Fri, 28 Oct 2016 09:51:42 +0200 Subject: [PATCH 7/8] Webpage now shows recently connected slaves, resolves #33 --- static/index.html | 9 +++++++ static/main.js | 62 ++++++++++++++++++++++++++++++++++------------- static/style.css | 16 ++++++++++++ 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/static/index.html b/static/index.html index c734eedf..4386f494 100644 --- a/static/index.html +++ b/static/index.html @@ -20,6 +20,9 @@ +
@@ -35,5 +38,11 @@
+
+

Slaves

+
+ +
+
\ No newline at end of file diff --git a/static/main.js b/static/main.js index c2bb3b98..56342d91 100644 --- a/static/main.js +++ b/static/main.js @@ -95,22 +95,24 @@ function drawcharts() { } // this is ugly, don't judge me var updateData = function(oldData){ - //console.log(piedata) - var labels = oldData["labels"]; - var dataSetA = oldData["datasets"][0]["data"]; - var dataSetB = oldData["datasets"][1]["data"]; - - labels.shift(); - count++; - labels.push(count.toString()); - // this is where we generate new data - var newDataA = piedata[0].value - piedataOld[0].value; - var newDataB = piedata[1].value - piedataOld[1].value; - // not quite sure how this works, where is dataSetA placed in data/the graph? - dataSetA.push(newDataA); - dataSetB.push(newDataB); - dataSetA.shift(); - dataSetB.shift(); + if(piedataOld[0]){ + //console.log(piedata) + var labels = oldData["labels"]; + var dataSetA = oldData["datasets"][0]["data"]; + var dataSetB = oldData["datasets"][1]["data"]; + + labels.shift(); + count++; + labels.push(count.toString()); + // this is where we generate new data + var newDataA = piedata[0].value - piedataOld[0].value; + var newDataB = piedata[1].value - piedataOld[1].value; + // not quite sure how this works, where is dataSetA placed in data/the graph? + dataSetA.push(newDataA); + dataSetB.push(newDataB); + dataSetA.shift(); + dataSetB.shift(); + } }; // Not sure why the scaleOverride isn't working... @@ -144,7 +146,9 @@ setTimeout(function(){ drawcharts(); },10) -var piedata = false; +var piedata = {}; +var piedataOld = {}; +// get cluster inventory from master setInterval(function() { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { @@ -181,6 +185,30 @@ setInterval(function() { xmlhttp.open("GET", "inventory", true); xmlhttp.send(); }, 500) +// get all slaves recently connected to master +Date.prototype.yyyymmdd = function() { // http://stackoverflow.com/questions/3066586/get-string-in-yyyymmdd-format-from-js-date-object + var mm = this.getMonth() + 1; // getMonth() is zero-based + var dd = this.getDate(); + return [this.getFullYear(), !mm[1] && '0', mm, !dd[1] && '0', dd].join(''); // padding +}; +var date = new Date(); +setInterval(function() { + var xmlhttp = new XMLHttpRequest(); + xmlhttp.onreadystatechange = function() { + if(xmlhttp.readyState == 4 && xmlhttp.status == 200) { + var slaveData = JSON.parse(xmlhttp.responseText); + var HTML = "

Latest connections:

" + for(i=0;i

Last seen: "+date.yyyymmdd(slaveData[key].time)+"

Port: "+slaveData[key].serverPort+"

Host: "+slaveData[key].mac+"

" + } + document.querySelector("#slaves > #display").innerHTML = HTML + } + } + xmlhttp.open("GET", "slaves", true); + xmlhttp.send(); +}, 500) // image data // key is the name of the item in the database, value is the name of the image on wiki.factorio.com/images/* diff --git a/static/style.css b/static/style.css index 995fcd40..ccb4648b 100644 --- a/static/style.css +++ b/static/style.css @@ -30,6 +30,22 @@ #contentGraph { float:left; } +/* Slave stuff */ +.slaveBox { + float:left; + width:200px; + height:110px; + background-color:#EEE; + border-radius: 10px; + margin-left:5px; + margin-right:5px; +} +.slaveBox > p { + margin:5px; +} +.slaveBox > h2 { + margin:5px; +} .button-black { width:100%; height:40px; From 09d511d0c8616fa4912a2819e995f68060d80e05 Mon Sep 17 00:00:00 2001 From: Danielv123 Date: Fri, 28 Oct 2016 10:51:46 +0200 Subject: [PATCH 8/8] No longer displays all subpages by default, performance on tab inactive --- static/main.js | 6 +++++- static/style.css | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/static/main.js b/static/main.js index 56342d91..86b02406 100644 --- a/static/main.js +++ b/static/main.js @@ -51,6 +51,7 @@ function drawcontents(data) { } // handle the navigation buttons +currentPage = "" function display(page) { var pages = document.querySelector("#body").childNodes; for(i=0;i div { + display:none; +} #contents { width:300px; }