From 98900e72dc05b92134b3b02f8bc9662c56bb849d Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Thu, 5 Sep 2019 18:06:50 +0200 Subject: [PATCH] Merge masterIP and masterPort into masterURL Merge the masterIP and masterPort configuration entries into a single masterURL entry. Fixes the problem with connecting to an HTTPS version of the master server and also makes it easier to host the master server behind a reverse proxy. This breaks all known code interfacing Clusterio. --- CHANGELOG.md | 3 +++ CLI tools/cluster_rcon.js | 5 ++-- CLI tools/delete_player.js | 2 +- README.md | 4 +-- client.js | 14 +++++----- config.json.dist | 4 +-- lib/clusterTools/getInstanceName.js | 2 +- sharedPlugins/UPSdisplay/index.js | 11 +++++--- sharedPlugins/clusterioMod/index.js | 27 +++++++++++++------ sharedPlugins/globalChat/index.js | 2 +- .../inventoryImports/interfacingFunctions.js | 23 +++++++++++----- .../interfacingFunctions.spec.js | 3 +-- sharedPlugins/researchSync/index.js | 6 ++--- sharedPlugins/researchSync/index.spec.js | 3 +-- sharedPlugins/statisticsExporter/index.js | 2 +- 15 files changed, 68 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0800b8a1..7c18c9ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,6 @@ Breaking Changes - Node.js versions below 10 are no longer supported. - lib/authenticate no longer requires config to be passed to it. Breaks playerManager. +- The masterIP and masterPort config entries has been merged into masterURL. + Breaks discordChat, playerManager, serverSelect, trainTeleports and + clusterioModel. diff --git a/CLI tools/cluster_rcon.js b/CLI tools/cluster_rcon.js index b62e6638..72808013 100644 --- a/CLI tools/cluster_rcon.js +++ b/CLI tools/cluster_rcon.js @@ -9,7 +9,6 @@ if(process.argv.length < 3){ process.exit(1) } -const masterIP = `${config.masterIP}:${config.masterPort}`; const token = config.masterAuthToken let commandArray = process.argv; commandArray.shift(); @@ -24,14 +23,14 @@ let command = commandArray.join(" "); let killBiters = `/silent-command local surface=game.surfaces[1] for key, entity in pairs(surface.find_entities_filtered({force="enemy"})) do entity.destroy() end`; (async ()=>{ - needle.post(masterIP+"/api/runCommand", { + needle.post(config.masterURL+"/api/runCommand", { broadcast:true, command, }, needleOptionsWithTokenAuthHeader, (err, resp) => { console.log(resp.body) }); // setInterval(()=>{ - // needle.post(masterIP+"/api/runCommand", { + // needle.post(config.masterURL+"/api/runCommand", { // broadcast:true, // command: killBiters, // }, needleOptionsWithTokenAuthHeader, (err, resp) => { diff --git a/CLI tools/delete_player.js b/CLI tools/delete_player.js index 1043935e..1adcdff6 100644 --- a/CLI tools/delete_player.js +++ b/CLI tools/delete_player.js @@ -11,7 +11,7 @@ if(!options.name){ process.exit(1) } -needle.post(config.masterIP+":"+config.masterPort+"/api/playerManager/deletePlayer", { +needle.post(config.masterURL+"/api/playerManager/deletePlayer", { name: options.name, token: options.token }, (err, resp) => { diff --git a/README.md b/README.md index 34add421..695077ad 100644 --- a/README.md +++ b/README.md @@ -203,9 +203,7 @@ reboot when you are done, then proceed to the next steps. *reboots matter* To connect to a master server running on a remote machine, open config.json with your favourite text editor (notepad++). You can also set it up to use the official server browser. -Change `masterIP `to something like `31.152.123.14` (provided by master server owner) - -Change `masterPort` to something like `8080` (provided by master server owner) +Change `masterURL `to something like `http://203.0.113.33:8080` (provided by master server owner) Change `masterAuthToken` to the value found in `secret-api-token.txt` on the master server diff --git a/client.js b/client.js index 6fa9a1c9..666bfc31 100644 --- a/client.js +++ b/client.js @@ -577,7 +577,7 @@ async function instanceManagement(instanceconfig) { console.log("Started instanceManagement();"); /* Open websocket connection to master */ - var socket = ioClient("http://"+config.masterIP+":"+config.masterPort); + var socket = ioClient(config.masterURL); socket.on("hello", data => { console.log("SOCKET | registering slave!"); socket.emit("registerSlave", { @@ -710,15 +710,15 @@ async function instanceManagement(instanceconfig) { } global.mac = mac; payload.mac = mac; - // console.log("Registered our presence with master "+config.masterIP+" at " + payload.time); - needle.post(config.masterIP + ":" + config.masterPort + '/api/getID', payload, needleOptionsWithTokenAuthHeader, function (err, response, body) { + // console.log("Registered our presence with master "+config.masterURL+" at " + payload.time); + needle.post(config.masterURL + '/api/getID', payload, needleOptionsWithTokenAuthHeader, function (err, response, body) { if (err && err.code != "ECONNRESET"){ - console.error("We got problems, something went wrong when contacting master"+config.masterIP+" at " + payload.time); + console.error("We got problems, something went wrong when contacting master "+config.masterURL+" at " + payload.time); console.error(err); } else 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. if(response.body !== "ok") { - console.log("Got no \"ok\" while registering our precense with master "+config.masterIP+" at " + payload.time); + console.log("Got no \"ok\" while registering our precense with master "+config.masterURL+" at " + payload.time); console.log(response.body); } } @@ -744,7 +744,7 @@ async function instanceManagement(instanceconfig) { modName: modHashes[i].modName, hash: modHashes[i].hash, }; - needle.post(config.masterIP + ":" + config.masterPort + '/api/checkMod', payload, needleOptionsWithTokenAuthHeader, function (err, response, body) { + needle.post(config.masterURL + '/api/checkMod', payload, needleOptionsWithTokenAuthHeader, function (err, response, body) { if(err) console.error("Unable to contact master server /api/checkMod! Please check your config.json."); if(response && body && body == "found") { console.log("master has mod "+modHashes[i].modName); @@ -754,7 +754,7 @@ async function instanceManagement(instanceconfig) { console.log("Sending mod: " + mod); // Send mods master says it wants // response.body is a string which is a modName.zip - var req = request.post({url: "http://"+config.masterIP + ":" + config.masterPort + '/api/uploadMod', + var req = request.post({url: config.masterURL + '/api/uploadMod', headers: { "x-access-token": config.masterAuthToken, }, diff --git a/config.json.dist b/config.json.dist index 9af0ace7..6fda38cd 100644 --- a/config.json.dist +++ b/config.json.dist @@ -7,8 +7,8 @@ "__comment1": "IP players should connect to to join your servers, should be portforwarded and stuff", "publicIP": "localhost", - "__comment2": "IP the master web server runs at, can be ignored on the master system", - "masterIP": "localhost", + "__comment2": "URL the master web server runs at, can be ignored on the master system. Must not end with a slash", + "masterURL": "http://localhost:8080", "__commentMasterPort": "HTTP port for the master to listen to", "masterPort": 8080, diff --git a/lib/clusterTools/getInstanceName.js b/lib/clusterTools/getInstanceName.js index 70a6b524..9632c4e5 100644 --- a/lib/clusterTools/getInstanceName.js +++ b/lib/clusterTools/getInstanceName.js @@ -8,7 +8,7 @@ module.exports = function(config){ return new Promise((resolve, reject) => { let instance = instances[instanceID]; if(!instance){ - needle.get(config.masterIP+":"+config.masterPort+ '/api/slaves', (err, response) => { + needle.get(config.masterURL + '/api/slaves', (err, response) => { if(err || response.statusCode != 200) { console.log("Unable to get JSON master/api/slaves, master might be unaccessible"); } else if (response && response.body) { diff --git a/sharedPlugins/UPSdisplay/index.js b/sharedPlugins/UPSdisplay/index.js index e8928abb..a373e21f 100644 --- a/sharedPlugins/UPSdisplay/index.js +++ b/sharedPlugins/UPSdisplay/index.js @@ -25,9 +25,14 @@ class UPSdisplay { let UPS = Math.round(ticksInPeriod / (timePeriod/1000)); // console.log("UPS: " + UPS); try{ - needle.post(this.config.masterIP+':'+this.config.masterPort+'/api/editSlaveMeta', {instanceID: this.config.unique, password: this.config.clientPassword, meta: {UPS:UPS, tick:this.tick}}, {headers: {'x-access-token': this.config.masterAuthToken}}, function(err, resp) { - // success? - }); + needle.post( + this.config.masterURL+'/api/editSlaveMeta', + {instanceID: this.config.unique, password: this.config.clientPassword, meta: {UPS:UPS, tick:this.tick}}, + {headers: {'x-access-token': this.config.masterAuthToken}}, + function(err, resp) { + // success? + } + ); } catch (err){ console.log(err); } diff --git a/sharedPlugins/clusterioMod/index.js b/sharedPlugins/clusterioMod/index.js index 9b2dc35d..01cd9be0 100644 --- a/sharedPlugins/clusterioMod/index.js +++ b/sharedPlugins/clusterioMod/index.js @@ -78,9 +78,14 @@ module.exports = class remoteCommands { } } console.log("Recorded flows, copper plate since last time: " + payload["copper-plate"]); - needle.post(that.config.masterIP + ":" + that.config.masterPort + '/api/logStats', {timestamp: timestamp, instanceID: that.config.unique, data: payload}, needleOptionsWithTokenAuthHeader, function (err, response, body) { - // we did it, keep going - }); + needle.post( + that.config.masterURL + '/api/logStats', + {timestamp: timestamp, instanceID: that.config.unique, data: payload}, + needleOptionsWithTokenAuthHeader, + function (err, response, body) { + // we did it, keep going + } + ); } oldTimestamp = timestamp; oldFlowStats = totalFlows; @@ -105,7 +110,7 @@ module.exports = class remoteCommands { 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(that.config.masterIP + ":" + that.config.masterPort + '/api/place', { + needle.post(that.config.masterURL + '/api/place', { name: g[0], count: g[1], instanceName: instance, // name of instance @@ -168,7 +173,7 @@ module.exports = class remoteCommands { // request our items, one item at a time for (let i = 0; i < Object.keys(preparedPackage).length; i++) { // console.log(preparedPackage[Object.keys(preparedPackage)[i]]); - needle.post(that.config.masterIP + ":" + that.config.masterPort + '/api/remove', preparedPackage[Object.keys(preparedPackage)[i]], needleOptionsWithTokenAuthHeader, function (err, response, body) { + function callback(err, response, body) { if (response && response.body && typeof response.body == "object") { // buffer confirmed orders confirmedOrders[confirmedOrders.length] = {name:response.body.name,count:response.body.count} @@ -176,7 +181,13 @@ module.exports = class remoteCommands { console.log(`Imported ${response.body.count} ${response.body.name} from master`); } } - }); + } + needle.post( + that.config.masterURL + '/api/remove', + preparedPackage[Object.keys(preparedPackage)[i]], + needleOptionsWithTokenAuthHeader, + callback + ); } // if we got some confirmed orders // console.log("Importing " + confirmedOrders.length + " items! " + JSON.stringify(confirmedOrders)); @@ -195,7 +206,7 @@ module.exports = class remoteCommands { // COMBINATOR SIGNALS --------------------------------------------------------- // get inventory from Master and RCON it to our slave setInterval(() => { - needle.get(that.config.masterIP + ":" + that.config.masterPort + '/api/inventory', function (err, response, body) { + needle.get(that.config.masterURL + '/api/inventory', function (err, response, body) { if(err){ console.error("Unable to get JSON master/api/inventory, master might be unaccessible"); } else if (response && response.body) { @@ -307,7 +318,7 @@ module.exports = class remoteCommands { return new Promise((resolve, reject) => { let instance = this.instances[instanceID]; if(!instance){ - needle.get(this.config.masterIP+":"+this.config.masterPort+ '/api/slaves', { compressed: true }, (err, response) => { + needle.get(this.config.masterURL + '/api/slaves', { compressed: true }, (err, response) => { if(err || response.statusCode != 200) { console.log("Unable to get JSON master/api/slaves, master might be unaccessible"); } else if (response && response.body) { diff --git a/sharedPlugins/globalChat/index.js b/sharedPlugins/globalChat/index.js index ad8a6c0e..7386c74d 100644 --- a/sharedPlugins/globalChat/index.js +++ b/sharedPlugins/globalChat/index.js @@ -55,7 +55,7 @@ module.exports = class remoteCommands { return new Promise((resolve, reject) => { let instance = this.instances[instanceID]; if(!instance){ - needle.get(this.config.masterIP+":"+this.config.masterPort+ '/api/slaves', { compressed: true }, (err, response) => { + needle.get(this.config.masterURL + '/api/slaves', { compressed: true }, (err, response) => { if(err || response.statusCode != 200) { console.log("Unable to get JSON master/api/slaves, master might be unaccessible"); } else if (response && response.body) { diff --git a/sharedPlugins/inventoryImports/interfacingFunctions.js b/sharedPlugins/inventoryImports/interfacingFunctions.js index 4b4736c6..870185d8 100644 --- a/sharedPlugins/inventoryImports/interfacingFunctions.js +++ b/sharedPlugins/inventoryImports/interfacingFunctions.js @@ -60,7 +60,7 @@ function handleInventory(json, config, callback){ } //console.log("Requesting: "+JSON.stringify(request)); // request the difference from master - needle.post(config.masterIP + ":" + config.masterPort + '/api/remove', request, {json:true,headers: {'x-access-token': config.masterAuthToken}}, function (err, response, body) { + function callback(err, response, body) { if (!err && response && response.body && (typeof response.body == "object" || isJson(response.body))) { // confirmed orders, already removed from master inventory //response.body.name: response.body.count @@ -70,7 +70,13 @@ function handleInventory(json, config, callback){ } else { collectStacks(false); } - }); + } + needle.post( + config.masterURL + '/api/remove', + request, + {json:true,headers: {'x-access-token': config.masterAuthToken}}, + callback + ); } else { collectStacks(false); } @@ -87,9 +93,14 @@ function handleInventory(json, config, callback){ for(let i = 0; i < stackArray.length; i++){ if(stackArray[i].count > 0){ // console.log("Returning overflow: " + JSON.stringify(stackArray[i])); - needle.post(config.masterIP + ":" + config.masterPort + '/api/place', stackArray[i], {headers: {'x-access-token': config.masterAuthToken}}, function (err, resp, body) { - // console.log(body); - }); + needle.post( + config.masterURL + '/api/place', + stackArray[i], + {headers: {'x-access-token': config.masterAuthToken}}, + function (err, resp, body) { + // console.log(body); + } + ); } } }); @@ -127,7 +138,7 @@ function pollInventories(outputFile){ //return "/silent-command "+'local a="{"for b,c in pairs(game.players)do if c.connected then local d=game.players[b].get_inventory(defines.inventory.player_main).get_contents()local e=game.players[b].get_quickbar().get_contents()local f={}for g=1,game.players[b].force.character_logistic_slot_count do f[g]=game.players[b].character.get_request_slot(g)end;a=a..b..":{inventory:{"for h,i in pairs(d)do a=a.."['+"'"+'"..h.."'+"'"+']:"..i..","end;for h,i in pairs(e)do a=a.."['+"'"+'"..h.."'+"'"+']:"..i..","end;a=a.."},requestSlots:{"for h,i in pairs(f)do a=a.."['+"'"+'"..i["name"].."'+"'"+']:"..i["count"]..", "end;a=a.."}},"end end;a=a.."}"game.write_file("'+outputFile+'",a)' return '/silent-command '+'local a='+"'"+'{"players":{'+"'"+'local b=false;for c,d in pairs(game.players)do if d.connected and d.character then if b then a=a..'+"'"+','+"'"+'else b=true end;local e=game.players[c].get_inventory(defines.inventory.player_main).get_contents()local f=game.players[c].get_quickbar().get_contents()local g={}local z={}for j,k in pairs(e)do if z[j] ~= nil then z[j] = z[j] + k else z[j] = k end end for j,k in pairs(f)do if z[j] ~= nil then z[j] = z[j] + k else z[j] = k end end for h=1,game.players[c].force.character_logistic_slot_count do g[h]=game.players[c].character.get_request_slot(h)end;a=a..'+"'"+'"'+"'"+'..c..'+"'"+'":{"inventory":{'+"'"+'local i=false;for j,k in pairs(z)do if i then a=a..'+"'"+','+"'"+'else i=true end;a=a..'+"'"+'"'+"'"+'..j..'+"'"+'":'+"'"+'..k end;a=a..'+"'"+'},"requestSlots":{'+"'"+'i=false;for j,k in pairs(g)do if i then a=a..'+"'"+','+"'"+'else i=true end;a=a..'+"'"+'"'+"'"+'..k['+"'"+'name'+"'"+']..'+"'"+'":'+"'"+'..k['+"'"+'count'+"'"+']end;a=a..'+"'"+'}}'+"'"+'end end;a=a.."}}"game.write_file("'+outputFile+'",a,true,0)' /* - needle.post(config.masterIP+':'+config.masterPort+'/api/editSlaveMeta', {instanceID: config.unique, password: config.clientPassword, meta: {UPS:UPS}}, function(err, resp) { + needle.post(config.masterURL+'/api/editSlaveMeta', {instanceID: config.unique, password: config.clientPassword, meta: {UPS:UPS}}, function(err, resp) { // success? }); */ diff --git a/sharedPlugins/inventoryImports/interfacingFunctions.spec.js b/sharedPlugins/inventoryImports/interfacingFunctions.spec.js index 3b1da5a4..44019395 100644 --- a/sharedPlugins/inventoryImports/interfacingFunctions.spec.js +++ b/sharedPlugins/inventoryImports/interfacingFunctions.spec.js @@ -12,8 +12,7 @@ const sinon = require("sinon"); describe("inventoryImports/interfacingFunctions.js", function(){ describe("handleInventory(inventory, config)", function(){ let config = { - masterIP:"localhost", - masterPort:8080, + masterURL:"http://localhost:8080", masterAuthToken:"", } it("returns false if given invalid input", function(){ diff --git a/sharedPlugins/researchSync/index.js b/sharedPlugins/researchSync/index.js index 45f36bbd..918d63e9 100644 --- a/sharedPlugins/researchSync/index.js +++ b/sharedPlugins/researchSync/index.js @@ -50,7 +50,7 @@ class ResearchSync { } initial_request_own_data(callback) { - const url = `${this.config.masterIP}:${this.config.masterPort}/api/getSlaveMeta` + const url = `${this.config.masterURL}/api/getSlaveMeta` const data = { instanceID: this.config.unique, password: this.config.clientPassword, @@ -102,7 +102,7 @@ class ResearchSync { } request_cluster_data() { - const slaves_data_url = `${this.config.masterIP}:${this.config.masterPort}/api/slaves` + const slaves_data_url = `${this.config.masterURL}/api/slaves` needle.get(slaves_data_url, {compressed:true}, this.sync_researches.bind(this)) } @@ -134,7 +134,7 @@ class ResearchSync { this.print_own_contribution() - needle.post(this.config.masterIP + ':' + this.config.masterPort + '/api/editSlaveMeta', { + needle.post(this.config.masterURL + '/api/editSlaveMeta', { instanceID: this.config.unique, password: this.config.clientPassword, meta: {research: this.research} diff --git a/sharedPlugins/researchSync/index.spec.js b/sharedPlugins/researchSync/index.spec.js index d97bdfdf..86a55552 100644 --- a/sharedPlugins/researchSync/index.spec.js +++ b/sharedPlugins/researchSync/index.spec.js @@ -12,8 +12,7 @@ describe("researchSync/index.js", function() { const config = { instanceName: "test", - masterIP: "localhost", - masterPort: 8080, + masterURL: "http://localhost:8080", unique: 99, clientPassword: "password", masterAuthToken: "masterToken", diff --git a/sharedPlugins/statisticsExporter/index.js b/sharedPlugins/statisticsExporter/index.js index fe03b9a1..dae7b24f 100644 --- a/sharedPlugins/statisticsExporter/index.js +++ b/sharedPlugins/statisticsExporter/index.js @@ -27,7 +27,7 @@ module.exports = class remoteCommands { force: force.forceName, forceData: JSON.stringify(force.data), }; - needle.post(`${mergedConfig.masterIP}:${mergedConfig.masterPort}/api/logStats`, + needle.post(`${mergedConfig.masterURL}/api/logStats`, request, needleOptionsWithTokenAuthHeader, (err, resp) => { if(!err && resp.body && resp.body.ok == false) console.log("Error calling /api/logStats: " + resp.body);