mirror of
https://github.com/sergeyyarkov/rconjs.git
synced 2026-10-11 02:18:56 +03:00
first
This commit is contained in:
commit
baf102b9ad
6
config.json
Normal file
6
config.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"host": "0.0.0.0",
|
||||
"port": 27015,
|
||||
"password": "password",
|
||||
"readlineEnabled": true
|
||||
}
|
||||
186
index.js
Normal file
186
index.js
Normal file
@ -0,0 +1,186 @@
|
||||
import { Buffer } from 'node:buffer';
|
||||
import net from 'node:net';
|
||||
import crypto from 'node:crypto';
|
||||
import config from './config.json' assert { type: 'json' };
|
||||
|
||||
var PACKET_TYPES = {
|
||||
SERVERDATA_AUTH: 3,
|
||||
SERVERDATA_AUTH_RESPONSE: 2,
|
||||
SERVERDATA_EXECCOMMAND: 2,
|
||||
SERVERDATA_RESPONSE_VALUE: 0,
|
||||
};
|
||||
|
||||
var rcon = await rcon_connect(config.host, config.port);
|
||||
await rcon.auth(config.password);
|
||||
|
||||
/**
|
||||
* Send commands using user input
|
||||
*/
|
||||
if (config.readlineEnabled) {
|
||||
var readline = await import('node:readline/promises');
|
||||
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||
rl.on('SIGINT', exit);
|
||||
|
||||
while (1) {
|
||||
var command = await rl.question('> ');
|
||||
if (command == '.exit') exit();
|
||||
console.log(`[RCON]: Executing "${command}"`);
|
||||
var response = await rcon.command(command);
|
||||
console.log(`[RCON]: Response:`, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Basic Packet Structure
|
||||
* Link: https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Basic_Packet_Structure
|
||||
*
|
||||
* @param {number} id
|
||||
* @param {number} type
|
||||
* @param {string} body
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
function rcon_create_packet_structure(id, type, body) {
|
||||
var size = Buffer.byteLength(body) + 14;
|
||||
var buffer = Buffer.alloc(size);
|
||||
|
||||
buffer.writeInt32LE(size - 4, 0);
|
||||
buffer.writeInt32LE(id, 4);
|
||||
buffer.writeInt32LE(type, 8);
|
||||
buffer.write(body, 12, size - 2, 'ascii');
|
||||
buffer.writeInt16LE(0x00, size - 2);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* The complete Triforce, or one or more components of the Triforce.
|
||||
* @typedef {Object} PacketStructure
|
||||
* @property {number} size
|
||||
* @property {number} id
|
||||
* @property {number} type
|
||||
* @property {string} body
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return object that contains packet data
|
||||
*
|
||||
* @param {Buffer} buffer
|
||||
* @returns {PacketStructure}
|
||||
*/
|
||||
function rcon_get_packet_structure(buffer) {
|
||||
return {
|
||||
size: buffer.readInt32LE(0),
|
||||
id: buffer.readInt32LE(4),
|
||||
type: buffer.readInt32LE(8),
|
||||
body: buffer.toString('ascii', 12, buffer.length - 2),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Will create a new socket
|
||||
*
|
||||
* @param {string} host
|
||||
* @param {number} port
|
||||
* @returns {Promise<net.Socket>}
|
||||
*/
|
||||
async function rcon_create_connection(host, port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var socket = net
|
||||
.createConnection(
|
||||
{
|
||||
host,
|
||||
port,
|
||||
},
|
||||
() => {
|
||||
console.log('[RCON]: Successfully connected to the server!');
|
||||
resolve(socket);
|
||||
}
|
||||
)
|
||||
.on('error', (error) => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new connection
|
||||
*
|
||||
* @param {string} host
|
||||
* @param {number} port
|
||||
*/
|
||||
async function rcon_connect(host, port) {
|
||||
try {
|
||||
var connection = await rcon_create_connection(host, port);
|
||||
|
||||
return {
|
||||
connection,
|
||||
|
||||
close() {
|
||||
connection.end();
|
||||
},
|
||||
|
||||
/**
|
||||
* Send RCON command
|
||||
*
|
||||
* @param {string} name
|
||||
* @returns
|
||||
*/
|
||||
async command(name) {
|
||||
var response = await this.send(
|
||||
rcon_create_packet_structure(
|
||||
crypto.randomInt(10000),
|
||||
PACKET_TYPES.SERVERDATA_EXECCOMMAND,
|
||||
name
|
||||
)
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Auhtenticate RCON client
|
||||
*
|
||||
* @param {string} password
|
||||
* @returns
|
||||
*/
|
||||
async auth(password) {
|
||||
var response = await this.send(
|
||||
rcon_create_packet_structure(10, PACKET_TYPES.SERVERDATA_AUTH, password)
|
||||
);
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
* Send RCON packet
|
||||
*
|
||||
* @param {PacketStructure} packet
|
||||
* @returns {Promise<PacketStructure>}
|
||||
*/
|
||||
async send(packet) {
|
||||
connection.write(packet);
|
||||
return new Promise((resolve, reject) => {
|
||||
connection.removeAllListeners('data');
|
||||
connection.removeAllListeners('error');
|
||||
connection.on('data', (data) => {
|
||||
var packet = rcon_get_packet_structure(data);
|
||||
|
||||
/**
|
||||
* Check on password valid
|
||||
*/
|
||||
if (packet.type === 2 && packet.id === -1) {
|
||||
throw new Error('Wrong RCON password!');
|
||||
}
|
||||
|
||||
resolve(packet);
|
||||
});
|
||||
connection.on('error', (error) => reject(error));
|
||||
});
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function exit() {
|
||||
console.log('\n[RCON]: Closing connection...');
|
||||
rcon.close();
|
||||
process.exit(1);
|
||||
}
|
||||
13
package.json
Normal file
13
package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "rcon",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node --no-warnings index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Sergey Yarkov",
|
||||
"license": "ISC"
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user