diff --git a/master.js b/master.js index f66663d9..c49195ed 100644 --- a/master.js +++ b/master.js @@ -38,6 +38,7 @@ const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); const crypto = require('crypto'); const base64url = require('base64url'); +const moment = require("moment"); // constants const config = require(args.config || './config'); @@ -99,6 +100,8 @@ app.use(function(req, res, next){ res.locals.res = res; res.locals.req = req; res.locals.masterPlugins = masterPlugins; + res.locals.slaves = slaves; + res.locals.moment = moment; next(); }); diff --git a/node_modules/_app/clusterTools/checkHotpatchInstallation.js b/node_modules/_app/clusterTools/checkHotpatchInstallation.js new file mode 100644 index 00000000..4ffb825f --- /dev/null +++ b/node_modules/_app/clusterTools/checkHotpatchInstallation.js @@ -0,0 +1,9 @@ +module.exports = async function checkHotpatchInstallation(messageInterface){ + let yn = await messageInterface("/silent-command if remote.interfaces['hotpatch'] then rcon.print('true') else rcon.print('false') end"); + yn = yn.replace(/(\r\n\t|\n|\r\t)/gm, ""); + if(yn == "true"){ + return true; + } else if(yn == "false"){ + return false; + } +} diff --git a/node_modules/_app/clusterTools/getCommand.js b/node_modules/_app/clusterTools/getCommand.js new file mode 100644 index 00000000..8d5afc11 --- /dev/null +++ b/node_modules/_app/clusterTools/getCommand.js @@ -0,0 +1,16 @@ +const fs = require("fs-extra"); + +const getLua = require("./getLua.js"); + +let commandCache; +module.exports = async function getCommand(file, COMPRESS = true){ + commandCache = commandCache || {}; + if(!commandCache[file]){ + commandCache[file] = await getLua(file); + return commandCache[file]; + } else if(typeof commandCache[file] == "string"){ + return commandCache[file]; + } else { + throw new Error("Command not found"); + } +} diff --git a/node_modules/_app/clusterTools/getInstanceName.js b/node_modules/_app/clusterTools/getInstanceName.js new file mode 100644 index 00000000..018242a7 --- /dev/null +++ b/node_modules/_app/clusterTools/getInstanceName.js @@ -0,0 +1,40 @@ +const needle = require("needle"); + +module.exports = function(config){ + const instances = []; + + if(config){ + return function getInstanceName(instanceID){ + return new Promise((resolve, reject) => { + let instance = instances[instanceID]; + if(!instance){ + needle.get(config.masterIP+":"+config.masterPort+ '/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) { + if(Buffer.isBuffer(response.body)) {console.log(response.body.toString("utf-8")); reject(new Error())} + try { + for (let index in response.body) + instances[index] = response.body[index].instanceName; + } catch (e){ + console.log(e); + return null; + } + instance = instances[instanceID] + if (!instance) instance = instanceID; //somehow the master doesn't know the instance + resolve(instance); + } + }); + } else { + resolve(instance); + } + }); + } + } else { + return async function thisAintGonnaWork(){ + let err = new Error("getInstanceName from _app/clusterTools needs to be called with {config} to work"); + console.log(err); + throw err; + } + } +} diff --git a/node_modules/_app/clusterTools/getLua.js b/node_modules/_app/clusterTools/getLua.js new file mode 100644 index 00000000..a54c8dac --- /dev/null +++ b/node_modules/_app/clusterTools/getLua.js @@ -0,0 +1,40 @@ +const fs = require("fs-extra"); + +module.exports = function getLua(filePath, COMPRESS_LUA = true){ + return new Promise((resolve, reject) => { + fs.readFile(filePath, "utf8", (err, contents) => { + if(err){ + reject(err); + } else { + // split content into lines + contents = contents.split(/\r?\n/); + + // join those lines after making them safe again + contents = contents.reduce((acc, val) => { + val = val.replace(/\\/g ,'\\\\'); + // remove leading and trailing spaces + val = val.trim(); + // escape single quotes + val = val.replace(/'/g ,'\\\''); + + // remove single line comments + let singleLineCommentPosition = val.indexOf("--"); + let multiLineCommentPosition = val.indexOf("--[["); + + if(multiLineCommentPosition === -1 && singleLineCommentPosition !== -1) { + val = val.substr(0, singleLineCommentPosition); + } + + return acc + val + '\\n'; + }, ""); // need the "" or it will not process the first row, potentially leaving a single line comment in that disables the whole code + + // console.log(contents); + + // this takes about 46 ms to minify train_stop_tracking.lua in my tests on an i3 6100u + if(COMPRESS_LUA) contents = require("luamin").minify(contents); + + resolve(contents); + } + }); + }); +} diff --git a/node_modules/_app/clusterTools/index.js b/node_modules/_app/clusterTools/index.js new file mode 100644 index 00000000..737b2d1d --- /dev/null +++ b/node_modules/_app/clusterTools/index.js @@ -0,0 +1,41 @@ +/** + +Functions frequently needed from different places in the cluster. Ex: + * Loading Lua scripts + * Checking if hotpatch is installed + * Getting an instance's displayname from their ID + +*/ + +module.exports = {config} => { + /** + async function to get Lua from a file, remove comments, minify and return. + + arg1 is the file path + arg2 is whether or not to compress the Lua. Makes debugging harder, but reduces bandwidth when many players are online. Recommended for polling commands. Defaults to true. + Promise resolves with a string of Lua. + */ + getLua: require("./getLua.js"), + /** + async function to check whether hotpatch is installed in a server. + + First argument is the servers async messageInterface for rcon return values + Promise resolves with boolean. + */ + checkHotpatchInstallation: require("./checkHotpatchInstallation.js"), + /** + async function to get an instances displayname from their instanceID + + arg1 is the instanceID + Promise resolves with a string, either the displayName or instanceID if not found. + */ + getInstanceName: require("./getInstanceName.js")(config), + /** + async function same as getLua, but using an in memory cache to lower FS operations. + + arg1 is the file path + arg2 is whether or not to compress, default true + Promise resolves with a string of Lua. + */ + getCommand: require("./getCommand.js"), +} \ No newline at end of file diff --git a/package.json b/package.json index 9e1bc980..f2dc4e69 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "minimist": "^1.2.0", "mkdirp": "^0.5.1", "mkdirp-promise": "^5.0.1", - "moment": "^2.20.1", + "moment": "^2.22.2", "ncp": "^2.0.0", "nedb": "^1.8.0", "needle": "^2.2.1",