ztavern/node-server-manager/Lib/RconConnection.js
2024-10-18 00:19:19 +00:00

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