196 lines
No EOL
5.9 KiB
JavaScript
196 lines
No EOL
5.9 KiB
JavaScript
const dgram = require('dgram')
|
|
const path = require('path')
|
|
const Utils = new (require(path.join(__dirname, '../Utils/Utils.js')))()
|
|
const Mutex = require(path.join(__dirname, '../Utils/Mutex.js'))
|
|
const fs = require('fs')
|
|
const wait = require('delay')
|
|
|
|
class Rcon {
|
|
constructor (ip, port, password, gamename) {
|
|
this.ip = ip
|
|
this.mutex = new Mutex()
|
|
this.port = port
|
|
this.password = password
|
|
this.gamename = gamename
|
|
this.commandPrefixes = fs.existsSync(path.join(__dirname, `./RconCommandPrefixes/${gamename}.js`))
|
|
? {...require(`./RconCommandPrefixes/Default.js`), ...require(`./RconCommandPrefixes/${gamename}.js`)}
|
|
: require(`./RconCommandPrefixes/Default.js`)
|
|
|
|
this.isRunning = false
|
|
this.commandRetries = 3
|
|
this.previousClients = []
|
|
this.canExecute = true
|
|
this.commandQueue = 0
|
|
this.client = dgram.createSocket('udp4')
|
|
}
|
|
|
|
async sendCommand(command) {
|
|
return new Promise(async (resolve, reject) => {
|
|
var client = dgram.createSocket('udp4')
|
|
var message = new Buffer.from(command, 'binary')
|
|
|
|
client.on('listening', async () => {
|
|
client.send(message, 0, message.length, this.port, this.ip, async (err) => {
|
|
if (err) {
|
|
client.close()
|
|
resolved = true
|
|
resolve(false)
|
|
}
|
|
})
|
|
})
|
|
|
|
client.bind()
|
|
|
|
var resolved = false;
|
|
var onMessage = (msg) => {
|
|
client.removeAllListeners()
|
|
client.close()
|
|
resolved = true
|
|
resolve(msg.toString())
|
|
}
|
|
|
|
client.on('message', onMessage);
|
|
|
|
setTimeout(() => {
|
|
if (!resolved) {
|
|
client.removeAllListeners()
|
|
client.close()
|
|
resolve(false)
|
|
}
|
|
}, 3000)
|
|
})
|
|
}
|
|
|
|
async executeCommandAsync(command) {
|
|
return new Promise(async (_resolve, reject) => {
|
|
if (this.commandPrefixes.Rcon.commandDelay) {
|
|
await this.mutex.lock()
|
|
}
|
|
|
|
const resolve = async (msg) => {
|
|
_resolve(msg)
|
|
|
|
if (this.commandPrefixes.Rcon.commandDelay) {
|
|
await wait(this.commandPrefixes.Rcon.commandDelay)
|
|
this.mutex.unlock()
|
|
}
|
|
}
|
|
|
|
const client = dgram.createSocket('udp4')
|
|
|
|
const message = new Buffer.from(Utils.formatString(this.commandPrefixes.Rcon.prefix, {
|
|
password: this.password,
|
|
command
|
|
})[0], 'binary')
|
|
|
|
const timeout = setTimeout(() => {
|
|
client.close()
|
|
client.removeAllListeners()
|
|
|
|
resolve(false)
|
|
}, 5000)
|
|
|
|
client.once('listening', async () => {
|
|
client.send(message, 0, message.length, this.port, this.ip, async (err) => {
|
|
if (err) {
|
|
clearTimeout(timeout)
|
|
client.close()
|
|
client.removeAllListeners()
|
|
|
|
resolve(false)
|
|
}
|
|
})
|
|
})
|
|
|
|
client.once('message', (data) => {
|
|
clearTimeout(timeout)
|
|
client.close()
|
|
|
|
resolve(data.toString())
|
|
})
|
|
|
|
client.bind()
|
|
})
|
|
}
|
|
|
|
async setDvar(dvar, value) {
|
|
const command = Utils.formatString(this.commandPrefixes.Rcon.setDvar, {
|
|
dvar,
|
|
value
|
|
})
|
|
|
|
await this.executeCommandAsync(command)
|
|
}
|
|
|
|
async getDvarRaw(dvarName) {
|
|
for (var i = 0; i < this.commandRetries; i++) {
|
|
var dvar = await this.executeCommandAsync(this.commandPrefixes.Rcon.getDvar.replace('%DVAR%', dvarName))
|
|
|
|
if (!dvar || !dvar.match(this.commandPrefixes.Rcon.dvarRegex)) continue
|
|
return this.commandPrefixes.Rcon.dvarRegex.exec(dvar)[3].trim()
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
async getDvar(dvar) {
|
|
const command = Utils.formatString(this.commandPrefixes.Rcon.getDvar, {
|
|
dvar
|
|
})
|
|
|
|
for (var i = 0; i < this.commandRetries; i++) {
|
|
const string = await this.executeCommandAsync(command)
|
|
|
|
if (!string || !string.match(this.commandPrefixes.Rcon.dvarRegex)) {
|
|
continue
|
|
}
|
|
|
|
return Utils.stripString(this.commandPrefixes.Rcon.dvarRegex.exec(string)[3].trim())
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
async getStatus() {
|
|
try {
|
|
var status = await this.executeCommandAsync(this.commandPrefixes.Rcon.status)
|
|
|
|
if (!status) return false
|
|
status = status.split('\n').slice(1, -1)
|
|
|
|
if (status[0].includes('invalid')) return false
|
|
|
|
var map = status[0].split(/\s+/g)[1]
|
|
var rawClients = status.slice(3)
|
|
var clients = []
|
|
|
|
rawClients.forEach(client => {
|
|
if (!client.match(this.commandPrefixes.Rcon.statusRegex)) return
|
|
var match = this.commandPrefixes.Rcon.statusRegex.exec(client)
|
|
|
|
for (var i = 0; i < match.length; i++) {
|
|
match[i] = match[i] ? match[i].trim() : ''
|
|
}
|
|
|
|
clients.push(this.commandPrefixes.Rcon.parseStatus(match))
|
|
})
|
|
}
|
|
catch (e) {
|
|
return false
|
|
}
|
|
|
|
return {success: true, data : {map, clients}}
|
|
}
|
|
|
|
async getClientByGuid(guid) {
|
|
var clients = (await this.getStatus()).data.clients
|
|
|
|
for (var i = 0; i < clients.length; i++) {
|
|
if (clients[i].guid == guid) {
|
|
return clients[i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = Rcon |