2017-08-24 09:15:06 +00:00
|
|
|
var _ = require('lodash')
|
|
|
|
var events = require('events')
|
|
|
|
var fs = require('fs')
|
|
|
|
var Gamedig = require('gamedig')
|
|
|
|
var slugify = require('slugify')
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var ArmaServer = require('arma-server')
|
2014-09-12 23:51:31 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var config = require('../config.js')
|
2015-04-03 10:23:17 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var queryInterval = 5000
|
2015-04-25 10:17:24 +00:00
|
|
|
var queryTypes = {
|
|
|
|
arma1: 'arma',
|
|
|
|
arma2: 'arma2',
|
|
|
|
arma2oa: 'arma2',
|
|
|
|
arma3: 'arma3',
|
2017-03-18 18:33:19 +00:00
|
|
|
arma3_x64: 'arma3',
|
2015-04-25 10:17:24 +00:00
|
|
|
cwa: 'operationflashpoint',
|
|
|
|
ofp: 'operationflashpoint',
|
2017-08-24 09:15:06 +00:00
|
|
|
ofpresistance: 'operationflashpoint'
|
|
|
|
}
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var createServerTitle = function (title) {
|
2015-08-15 11:56:43 +00:00
|
|
|
if (config.prefix) {
|
2017-08-24 09:15:06 +00:00
|
|
|
title = config.prefix + title
|
2015-08-15 11:56:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (config.suffix) {
|
2017-08-24 09:15:06 +00:00
|
|
|
title = title + config.suffix
|
2015-08-15 11:56:43 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
return title
|
|
|
|
}
|
2015-08-15 11:56:43 +00:00
|
|
|
|
2015-10-31 14:27:16 +00:00
|
|
|
var Server = function (config, logs, options) {
|
2017-08-24 09:15:06 +00:00
|
|
|
this.config = config
|
|
|
|
this.logs = logs
|
|
|
|
this.update(options)
|
|
|
|
}
|
2014-06-04 22:19:54 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
Server.prototype = new events.EventEmitter()
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2017-03-31 15:08:56 +00:00
|
|
|
Server.prototype.generateId = function () {
|
2017-08-24 09:15:06 +00:00
|
|
|
return slugify(this.title).replace(/\./g, '-')
|
|
|
|
}
|
2017-03-31 15:08:56 +00:00
|
|
|
|
2014-09-12 23:51:31 +00:00
|
|
|
Server.prototype.update = function (options) {
|
2019-05-22 14:21:28 +00:00
|
|
|
this.additionalConfigurationOptions = options.additionalConfigurationOptions
|
2017-08-24 09:15:06 +00:00
|
|
|
this.admin_password = options.admin_password
|
2017-10-01 14:58:30 +00:00
|
|
|
this.allowed_file_patching = options.allowed_file_patching
|
2017-08-24 09:15:06 +00:00
|
|
|
this.auto_start = options.auto_start
|
|
|
|
this.battle_eye = options.battle_eye
|
2017-10-01 14:58:30 +00:00
|
|
|
this.file_patching = options.file_patching
|
2017-09-30 19:49:42 +00:00
|
|
|
this.forcedDifficulty = options.forcedDifficulty || null
|
2017-08-24 09:15:06 +00:00
|
|
|
this.max_players = options.max_players
|
|
|
|
this.missions = options.missions
|
|
|
|
this.mods = options.mods || []
|
2017-09-30 19:49:42 +00:00
|
|
|
this.motd = options.motd || null
|
2017-08-24 09:15:06 +00:00
|
|
|
this.number_of_headless_clients = options.number_of_headless_clients || 0
|
|
|
|
this.password = options.password
|
|
|
|
this.parameters = options.parameters
|
|
|
|
this.persistent = options.persistent
|
|
|
|
this.port = options.port || 2302
|
|
|
|
this.title = options.title
|
|
|
|
this.von = options.von
|
|
|
|
this.verify_signatures = options.verify_signatures
|
|
|
|
|
|
|
|
this.id = this.generateId()
|
|
|
|
this.port = parseInt(this.port, 10) // If port is a string then gamedig fails
|
|
|
|
}
|
|
|
|
|
|
|
|
Server.prototype.queryStatus = function () {
|
2015-10-31 13:35:50 +00:00
|
|
|
if (!this.instance) {
|
2017-08-24 09:15:06 +00:00
|
|
|
return
|
2015-10-31 13:35:50 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var self = this
|
2014-11-09 18:07:00 +00:00
|
|
|
Gamedig.query(
|
2015-04-25 10:17:48 +00:00
|
|
|
{
|
|
|
|
type: queryTypes[config.game],
|
|
|
|
host: '127.0.0.1',
|
2017-08-24 09:15:06 +00:00
|
|
|
port: self.port
|
2015-04-25 10:17:48 +00:00
|
|
|
},
|
2017-08-24 09:15:06 +00:00
|
|
|
function (state) {
|
2015-10-31 13:35:50 +00:00
|
|
|
if (!self.instance) {
|
2017-08-24 09:15:06 +00:00
|
|
|
return
|
2015-10-31 13:35:50 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
if (state.error) {
|
|
|
|
self.state = null
|
2015-04-25 10:17:48 +00:00
|
|
|
} else {
|
2017-08-24 09:15:06 +00:00
|
|
|
self.state = state
|
2015-04-25 10:17:48 +00:00
|
|
|
}
|
2015-01-21 02:18:45 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
self.emit('state')
|
2015-04-25 10:17:48 +00:00
|
|
|
}
|
2017-08-24 09:15:06 +00:00
|
|
|
)
|
|
|
|
}
|
2014-11-09 18:07:00 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
Server.prototype.getParameters = function () {
|
|
|
|
var parameters = []
|
2016-11-19 22:31:38 +00:00
|
|
|
|
|
|
|
if (config.parameters && Array.isArray(config.parameters)) {
|
2017-08-24 09:15:06 +00:00
|
|
|
parameters = parameters.concat(config.parameters)
|
2016-11-19 22:31:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.parameters && Array.isArray(this.parameters)) {
|
2017-08-24 09:15:06 +00:00
|
|
|
parameters = parameters.concat(this.parameters)
|
2016-11-19 22:31:38 +00:00
|
|
|
}
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
return parameters
|
2017-09-11 09:28:47 +00:00
|
|
|
}
|
|
|
|
|
2019-05-22 14:21:28 +00:00
|
|
|
Server.prototype.getAdditionalConfigurationOptions = function () {
|
|
|
|
var additionalConfigurationOptions = ''
|
|
|
|
|
|
|
|
if (config.additionalConfigurationOptions) {
|
|
|
|
additionalConfigurationOptions += config.additionalConfigurationOptions
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.additionalConfigurationOptions) {
|
|
|
|
if (additionalConfigurationOptions) {
|
|
|
|
additionalConfigurationOptions += '\n'
|
|
|
|
}
|
|
|
|
|
|
|
|
additionalConfigurationOptions += this.additionalConfigurationOptions
|
|
|
|
}
|
|
|
|
|
|
|
|
return additionalConfigurationOptions
|
|
|
|
}
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
Server.prototype.start = function () {
|
2018-01-02 13:30:39 +00:00
|
|
|
if (this.instance) {
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var parameters = this.getParameters()
|
2015-02-13 16:13:55 +00:00
|
|
|
var server = new ArmaServer.Server({
|
2019-05-22 14:21:28 +00:00
|
|
|
additionalConfigurationOptions: this.getAdditionalConfigurationOptions(),
|
2017-09-30 18:42:18 +00:00
|
|
|
admins: config.admins,
|
2017-10-01 14:58:30 +00:00
|
|
|
allowedFilePatching: this.allowed_file_patching || 1,
|
2014-09-12 23:51:31 +00:00
|
|
|
battleEye: this.battle_eye ? 1 : 0,
|
|
|
|
config: this.id,
|
2015-01-16 21:50:31 +00:00
|
|
|
disableVoN: this.von ? 0 : 1,
|
2015-04-03 10:23:17 +00:00
|
|
|
game: config.game,
|
2017-10-01 14:58:30 +00:00
|
|
|
filePatching: this.file_patching || false,
|
2017-09-30 19:49:42 +00:00
|
|
|
forcedDifficulty: this.forcedDifficulty || null,
|
2017-08-24 09:15:06 +00:00
|
|
|
headlessClients: this.number_of_headless_clients > 0 ? ['127.0.0.1'] : null,
|
2015-08-15 11:56:43 +00:00
|
|
|
hostname: createServerTitle(this.title),
|
2017-08-24 09:15:06 +00:00
|
|
|
localClient: this.number_of_headless_clients > 0 ? ['127.0.0.1'] : null,
|
2015-08-23 22:16:16 +00:00
|
|
|
missions: this.missions,
|
2014-09-12 23:51:31 +00:00
|
|
|
mods: this.mods,
|
2017-09-30 19:49:42 +00:00
|
|
|
motd: (this.motd && this.motd.split('\n')) || null,
|
2016-11-19 22:31:38 +00:00
|
|
|
parameters: parameters,
|
2014-09-12 23:51:31 +00:00
|
|
|
password: this.password,
|
|
|
|
passwordAdmin: this.admin_password,
|
2015-10-31 14:27:16 +00:00
|
|
|
path: this.config.path,
|
2014-09-12 23:51:31 +00:00
|
|
|
persistent: this.persistent ? 1 : 0,
|
2015-10-31 14:27:16 +00:00
|
|
|
platform: this.config.type,
|
2014-09-12 23:51:31 +00:00
|
|
|
players: this.max_players,
|
|
|
|
port: this.port,
|
2016-04-24 17:07:43 +00:00
|
|
|
serverMods: config.serverMods,
|
2017-08-24 09:15:06 +00:00
|
|
|
verifySignatures: this.verify_signatures ? 2 : 0
|
|
|
|
})
|
|
|
|
server.writeServerConfig()
|
|
|
|
var instance = server.start()
|
|
|
|
var self = this
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var logStream = null
|
2015-10-31 14:27:16 +00:00
|
|
|
if (this.config.type === 'linux') {
|
|
|
|
logStream = fs.createWriteStream(this.logs.generateLogFilePath(), {
|
2019-09-22 19:53:16 +00:00
|
|
|
flags: 'a'
|
2017-08-24 09:15:06 +00:00
|
|
|
})
|
2015-10-31 14:27:16 +00:00
|
|
|
}
|
|
|
|
|
2014-11-24 00:56:54 +00:00
|
|
|
instance.stdout.on('data', function (data) {
|
2015-10-31 14:27:16 +00:00
|
|
|
if (logStream) {
|
2017-08-24 09:15:06 +00:00
|
|
|
logStream.write(data)
|
2015-10-31 14:27:16 +00:00
|
|
|
}
|
2017-08-24 09:15:06 +00:00
|
|
|
})
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2014-11-24 00:56:54 +00:00
|
|
|
instance.stderr.on('data', function (data) {
|
2015-10-31 14:27:16 +00:00
|
|
|
if (logStream) {
|
2017-08-24 09:15:06 +00:00
|
|
|
logStream.write(data)
|
2015-10-31 14:27:16 +00:00
|
|
|
}
|
2017-08-24 09:15:06 +00:00
|
|
|
})
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2014-11-24 00:56:54 +00:00
|
|
|
instance.on('close', function (code) {
|
2016-06-12 13:11:38 +00:00
|
|
|
if (logStream) {
|
2017-08-24 09:15:06 +00:00
|
|
|
logStream.end()
|
2016-06-12 13:11:38 +00:00
|
|
|
}
|
2015-10-31 14:27:16 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
clearInterval(self.queryStatusInterval)
|
|
|
|
self.state = null
|
|
|
|
self.pid = null
|
|
|
|
self.instance = null
|
2014-11-09 18:07:00 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
self.stopHeadlessClients()
|
2017-09-11 09:28:47 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
self.emit('state')
|
|
|
|
})
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2017-04-01 10:46:39 +00:00
|
|
|
instance.on('error', function (err) {
|
2017-08-24 09:15:06 +00:00
|
|
|
console.log(err)
|
|
|
|
})
|
2017-04-01 10:46:39 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
this.pid = instance.pid
|
|
|
|
this.instance = instance
|
2014-11-09 18:07:00 +00:00
|
|
|
this.queryStatusInterval = setInterval(function () {
|
2017-08-24 09:15:06 +00:00
|
|
|
self.queryStatus()
|
|
|
|
}, queryInterval)
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2017-09-11 09:28:47 +00:00
|
|
|
this.startHeadlessClients()
|
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
this.emit('state')
|
2017-09-11 09:28:47 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
return this
|
|
|
|
}
|
2017-09-11 09:28:47 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
Server.prototype.startHeadlessClients = function () {
|
|
|
|
var parameters = this.getParameters()
|
|
|
|
var self = this
|
2017-09-11 09:28:47 +00:00
|
|
|
var headlessClientInstances = _.times(this.number_of_headless_clients, function (i) {
|
2015-02-13 16:13:55 +00:00
|
|
|
var headless = new ArmaServer.Headless({
|
2017-10-01 14:58:30 +00:00
|
|
|
filePatching: self.file_patching,
|
2015-04-03 10:23:17 +00:00
|
|
|
game: config.game,
|
2017-08-24 09:15:06 +00:00
|
|
|
host: '127.0.0.1',
|
2017-09-11 09:28:47 +00:00
|
|
|
mods: self.mods,
|
2016-11-19 22:31:38 +00:00
|
|
|
parameters: parameters,
|
2017-09-11 09:28:47 +00:00
|
|
|
password: self.password,
|
|
|
|
path: self.config.path,
|
|
|
|
platform: self.config.type,
|
2017-08-24 09:15:06 +00:00
|
|
|
port: self.port
|
|
|
|
})
|
|
|
|
var headlessInstance = headless.start()
|
|
|
|
var name = 'HC_' + i
|
|
|
|
var logPrefix = self.id + ' ' + name
|
|
|
|
console.log(logPrefix + ' starting')
|
2015-02-13 16:13:55 +00:00
|
|
|
|
|
|
|
headlessInstance.stdout.on('data', function (data) {
|
2017-08-24 09:15:06 +00:00
|
|
|
console.log(logPrefix + ' stdout: ' + data)
|
|
|
|
})
|
2015-02-13 16:13:55 +00:00
|
|
|
|
|
|
|
headlessInstance.stderr.on('data', function (data) {
|
2017-08-24 09:15:06 +00:00
|
|
|
console.log(logPrefix + ' stderr: ' + data)
|
|
|
|
})
|
2015-02-13 16:13:55 +00:00
|
|
|
|
|
|
|
headlessInstance.on('close', function (code) {
|
2017-08-24 09:15:06 +00:00
|
|
|
console.log(logPrefix + ' exited: ' + code)
|
2017-09-11 09:28:47 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
var elementIndex = headlessClientInstances.indexOf(headlessInstance)
|
|
|
|
if (elementIndex !== -1) {
|
|
|
|
headlessClientInstances.splice(elementIndex, 1)
|
2017-09-11 09:28:47 +00:00
|
|
|
}
|
2017-08-24 09:15:06 +00:00
|
|
|
})
|
2015-02-13 16:13:55 +00:00
|
|
|
|
2017-04-01 10:46:39 +00:00
|
|
|
headlessInstance.on('error', function (err) {
|
2017-08-24 09:15:06 +00:00
|
|
|
console.log(logPrefix + ' error: ' + err)
|
|
|
|
})
|
2017-04-01 10:46:39 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
return headlessInstance
|
|
|
|
})
|
2015-02-13 16:13:55 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
this.headlessClientInstances = headlessClientInstances
|
2017-09-11 09:28:47 +00:00
|
|
|
}
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
Server.prototype.stop = function (cb) {
|
|
|
|
var handled = false
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2014-11-24 00:56:54 +00:00
|
|
|
this.instance.on('close', function (code) {
|
2014-04-06 22:58:17 +00:00
|
|
|
if (!handled) {
|
2017-08-24 09:15:06 +00:00
|
|
|
handled = true
|
2014-06-04 23:02:09 +00:00
|
|
|
|
|
|
|
if (cb) {
|
2017-08-24 09:15:06 +00:00
|
|
|
cb()
|
2014-06-04 23:02:09 +00:00
|
|
|
}
|
2014-04-06 22:58:17 +00:00
|
|
|
}
|
2017-08-24 09:15:06 +00:00
|
|
|
})
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
this.instance.kill()
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
setTimeout(function () {
|
2014-04-06 22:58:17 +00:00
|
|
|
if (!handled) {
|
2017-08-24 09:15:06 +00:00
|
|
|
handled = true
|
2014-06-04 23:02:09 +00:00
|
|
|
|
|
|
|
if (cb) {
|
2017-08-24 09:15:06 +00:00
|
|
|
cb()
|
2014-06-04 23:02:09 +00:00
|
|
|
}
|
2014-04-06 22:58:17 +00:00
|
|
|
}
|
2017-08-24 09:15:06 +00:00
|
|
|
}, 5000)
|
2014-04-06 22:58:17 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
return this
|
|
|
|
}
|
2014-06-04 22:17:18 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
Server.prototype.stopHeadlessClients = function () {
|
2017-09-11 09:28:47 +00:00
|
|
|
this.headlessClientInstances.map(function (headlessClientInstance) {
|
2017-08-24 09:15:06 +00:00
|
|
|
headlessClientInstance.kill()
|
|
|
|
})
|
2017-09-11 09:28:47 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 22:17:18 +00:00
|
|
|
Server.prototype.toJSON = function () {
|
|
|
|
return {
|
2019-05-22 14:21:28 +00:00
|
|
|
additionalConfigurationOptions: this.additionalConfigurationOptions,
|
2014-09-12 23:51:31 +00:00
|
|
|
admin_password: this.admin_password,
|
2017-10-01 14:58:30 +00:00
|
|
|
allowed_file_patching: this.allowed_file_patching,
|
2017-02-20 08:44:07 +00:00
|
|
|
auto_start: this.auto_start,
|
2014-09-12 23:51:31 +00:00
|
|
|
battle_eye: this.battle_eye,
|
2014-06-04 22:17:18 +00:00
|
|
|
id: this.id,
|
2017-10-03 08:56:58 +00:00
|
|
|
file_patching: this.file_patching,
|
2017-09-30 19:49:42 +00:00
|
|
|
forcedDifficulty: this.forcedDifficulty,
|
2014-09-12 23:51:31 +00:00
|
|
|
max_players: this.max_players,
|
2015-08-23 22:16:16 +00:00
|
|
|
missions: this.missions,
|
2017-09-30 19:49:42 +00:00
|
|
|
motd: this.motd,
|
2014-06-04 22:17:18 +00:00
|
|
|
mods: this.mods,
|
2017-09-11 09:28:47 +00:00
|
|
|
number_of_headless_clients: this.number_of_headless_clients,
|
2016-11-19 22:31:38 +00:00
|
|
|
parameters: this.parameters,
|
2014-09-12 23:51:31 +00:00
|
|
|
password: this.password,
|
|
|
|
persistent: this.persistent,
|
2014-06-04 22:17:18 +00:00
|
|
|
pid: this.pid,
|
2014-09-12 23:51:31 +00:00
|
|
|
port: this.port,
|
2014-11-09 18:07:00 +00:00
|
|
|
state: this.state,
|
2014-09-12 23:51:31 +00:00
|
|
|
title: this.title,
|
|
|
|
von: this.von,
|
2017-08-24 09:15:06 +00:00
|
|
|
verify_signatures: this.verify_signatures
|
|
|
|
}
|
|
|
|
}
|
2014-02-13 22:47:51 +00:00
|
|
|
|
2017-08-24 09:15:06 +00:00
|
|
|
module.exports = Server
|