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..a7c8ee97 100644 --- a/client.js +++ b/client.js @@ -1,35 +1,125 @@ 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]; +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.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": 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 createSave = child_process.spawnSync( + './' + config.factorioDirectory + '/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( + './' + config.factorioDirectory + '/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!'); }).on('connected', function() { console.log('Connected!'); + getID(); }).on('disconnected', function() { console.log('Disconnected!'); // now reconnect @@ -39,22 +129,45 @@ 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(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]) { 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]}, + needle.post(config.masterIP + ":" + config.masterPort + '/place', {name:g[0], count:g[1]}, function(err, resp, body){ // console.log(body); }); @@ -64,10 +177,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++) { @@ -99,7 +212,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 @@ -118,7 +231,7 @@ setInterval(function() { for(i = 0;i

Production

+
@@ -35,5 +38,11 @@
+
+

Slaves

+
+ +
+
\ No newline at end of file diff --git a/static/main.js b/static/main.js index 319db5b2..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

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/* 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 +250,4 @@ var imagedata = { ["piercing-shotgun-shells"]: "Piercing-shotgun-shell", ["accumulator"]: "Basic-accumulator", ["beacon"]: "Basic-beacon", - } diff --git a/static/style.css b/static/style.css index 995fcd40..d2a2fc76 100644 --- a/static/style.css +++ b/static/style.css @@ -16,6 +16,9 @@ #body { margin-left:200px; } +#body > div { + display:none; +} #contents { width:300px; } @@ -30,6 +33,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;