From 7a44f622aa36426e19fe906998569145ddfa4d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Dahlgren?= Date: Mon, 13 Apr 2020 14:42:31 +0200 Subject: [PATCH] Virtual server folder with keys management --- lib/server.js | 129 ++++++++++++++++++++++++++++++++++++++++++++++---- package.json | 1 + 2 files changed, 121 insertions(+), 9 deletions(-) diff --git a/lib/server.js b/lib/server.js index 65f39166..dd14a787 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,7 +1,10 @@ var _ = require('lodash') var events = require('events') var fs = require('fs') +var fsExtra = require('fs.extra') var Gamedig = require('gamedig') +var glob = require('glob') +var path = require('path') var slugify = require('slugify') var ArmaServer = require('arma-server') @@ -134,6 +137,104 @@ Server.prototype.start = function () { return this } + var self = this + + const requiredFileExtensions = ['.dll', '.exe', '.so', '.txt'] + const serverFolders = [ + 'addons', + 'argo', + 'battleye', + 'contact', + 'curator', + 'dll', + 'dta', + 'enoch', + 'expansion', + 'gm', + 'heli', + 'jets', + 'kart', + 'mark', + 'mpmissions', + 'orange', + 'tacops', + 'tank' + ] + const symlinkFolders = serverFolders.concat(self.mods).concat(config.serverMods) + + return fs.promises.mkdtemp(path.join(self.config.path, 'arma-server-')) + .then((serverFolder) => { + self.virtualServerFolder = serverFolder + console.log('Created virtual server folder:', serverFolder) + + return fs.promises.readdir(self.config.path) + .then((files) => { + // Copy needed files, file symlinks on Windows are sketchy + const serverFiles = files.filter((file) => requiredFileExtensions.indexOf(path.extname(file)) >= 0 || path.basename(file) === 'arma3server') + return Promise.all(serverFiles.map((file) => { + return fs.promises.copyFile(path.join(self.config.path, file), path.join(serverFolder, file)) + })) + }) + .then(() => { + // Create virtual folders from default Arma and mods + return Promise.all(symlinkFolders.map((symlink) => { + return fs.promises.access(path.join(self.config.path, symlink)) + .then(() => { + return fs.promises.symlink(path.join(self.config.path, symlink), path.join(serverFolder, symlink), 'junction') + }) + .catch((err) => { + console.error('Could create symlink for', symlink, 'due to', err) + }) + })) + }) + .then(() => { + // Copy needed keys, file symlinks on Windows are sketchy + const keysFolder = path.join(serverFolder, 'keys') + return fs.promises.mkdir(keysFolder, { recursive: true }) + .then(() => { + const defaultKeysPath = path.join(self.config.path, 'keys') + const defaultKeysPromise = fs.promises.readdir(defaultKeysPath) + .then((files) => files.filter((file) => path.extname(file) === '.bikey')) + .then((files) => files.map((file) => path.join(defaultKeysPath, file))) + + const modKeysPromise = Promise.all(self.mods.map(mod => { + return new Promise((resolve, reject) => { + const modPath = path.join(this.config.path, mod) + glob(`${modPath}/**/*.bikey`, function (err, files) { + if (err) { + return reject(err) + } + + return resolve(files) + }) + }) + })).then((modsFiles) => modsFiles.flat()) + + return Promise.all([defaultKeysPromise, modKeysPromise].map((promise) => { + return promise.then((keyFiles) => { + return Promise.all(keyFiles.map((keyFile) => { + return fs.promises.copyFile(keyFile, path.join(keysFolder, path.basename(keyFile))) + })) + }) + })).catch((err) => { + console.error('Error copying keys:', err) + }) + }) + }) + .then(() => { + self.realStart(serverFolder) + }) + .catch((err) => { + console.error('Error creating virtual server folder:', err) + }) + }) +} + +Server.prototype.realStart = function (path) { + if (this.instance) { + return this + } + var parameters = this.getParameters() var server = new ArmaServer.Server({ additionalConfigurationOptions: this.getAdditionalConfigurationOptions(), @@ -154,7 +255,7 @@ Server.prototype.start = function () { parameters: parameters, password: this.password, passwordAdmin: this.admin_password, - path: this.config.path, + path: path, persistent: this.persistent ? 1 : 0, platform: this.config.type, players: this.max_players, @@ -196,8 +297,18 @@ Server.prototype.start = function () { self.instance = null self.stopHeadlessClients() - - self.emit('state') + .then(() => { + if (self.virtualServerFolder) { + fsExtra.rmrf(self.virtualServerFolder, function (err) { + if (err) { + console.log('Error removing virtual server folder', err) + } + }) + self.virtualServerFolder = null + } + + self.emit('state') + }) }) instance.on('error', function (err) { @@ -210,14 +321,14 @@ Server.prototype.start = function () { self.queryStatus() }, queryInterval) - this.startHeadlessClients() + this.startHeadlessClients(path) this.emit('state') return this } -Server.prototype.startHeadlessClients = function () { +Server.prototype.startHeadlessClients = function (path) { var parameters = this.getParameters() var self = this var headlessClientInstances = _.times(this.number_of_headless_clients, function (i) { @@ -228,7 +339,7 @@ Server.prototype.startHeadlessClients = function () { mods: self.mods, parameters: parameters, password: self.password, - path: self.config.path, + path: path, platform: self.config.type, port: self.port }) @@ -293,9 +404,9 @@ Server.prototype.stop = function (cb) { } Server.prototype.stopHeadlessClients = function () { - this.headlessClientInstances.map(function (headlessClientInstance) { - headlessClientInstance.kill() - }) + return Promise.all(this.headlessClientInstances.map(function (headlessClientInstance) { + return headlessClientInstance.kill() + })) } Server.prototype.toJSON = function () { diff --git a/package.json b/package.json index 1a886d36..c8b289af 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "filesize": "^3.1.0", "fs.extra": "~1.3.2", "gamedig": "^0.2.30", + "glob": "^7.1.6", "jquery": "^3.5.0", "jquery.iframe-transport": "^1.0.0", "ladda": "1.0.5",