Implement RCON (#72)
This commit is contained in:
parent
24c7f0e155
commit
038c4a44d5
11
package-lock.json
generated
11
package-lock.json
generated
@ -12,6 +12,7 @@
|
|||||||
"mongodb": "^4.8.0",
|
"mongodb": "^4.8.0",
|
||||||
"node-kcp-token": "github:memetrollsxd/node-kcp",
|
"node-kcp-token": "github:memetrollsxd/node-kcp",
|
||||||
"protobufjs": "^7.0.0",
|
"protobufjs": "^7.0.0",
|
||||||
|
"rcon-server": "^0.1.1",
|
||||||
"typescript": "^4.7.4"
|
"typescript": "^4.7.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -1202,6 +1203,11 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rcon-server": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rcon-server/-/rcon-server-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-oJ9+s0yxGc7in6GBBBxFXKRY2OyIVxFsoAEHlo5iFXDCuK6O4gY4qJ9XndMBVmA+nABkyOrN6QAFzoE6wZiI7A=="
|
||||||
|
},
|
||||||
"node_modules/readdirp": {
|
"node_modules/readdirp": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
@ -2568,6 +2574,11 @@
|
|||||||
"unpipe": "1.0.0"
|
"unpipe": "1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rcon-server": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rcon-server/-/rcon-server-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-oJ9+s0yxGc7in6GBBBxFXKRY2OyIVxFsoAEHlo5iFXDCuK6O4gY4qJ9XndMBVmA+nABkyOrN6QAFzoE6wZiI7A=="
|
||||||
|
},
|
||||||
"readdirp": {
|
"readdirp": {
|
||||||
"version": "3.6.0",
|
"version": "3.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"mongodb": "^4.8.0",
|
"mongodb": "^4.8.0",
|
||||||
"node-kcp-token": "github:memetrollsxd/node-kcp",
|
"node-kcp-token": "github:memetrollsxd/node-kcp",
|
||||||
"protobufjs": "^7.0.0",
|
"protobufjs": "^7.0.0",
|
||||||
|
"rcon-server": "^0.1.1",
|
||||||
"typescript": "^4.7.4"
|
"typescript": "^4.7.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -27,13 +27,24 @@ export default class Interface {
|
|||||||
|
|
||||||
private constructor() { }
|
private constructor() { }
|
||||||
|
|
||||||
public static readonly start = () => {
|
public static start() {
|
||||||
Interface.rl.question("", (_command) => {
|
Interface.rl.question("", (_command) => {
|
||||||
if (!_command) {
|
if (!_command) {
|
||||||
Interface.start();
|
Interface.start();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const cmd = new Command(_command);
|
const cmd = new Command(_command);
|
||||||
|
Interface.handle(cmd);
|
||||||
|
Interface.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
Interface.rl.on('close', () => {
|
||||||
|
console.log('Have a great day!');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static handle(cmd: Command) {
|
||||||
import(`./${alias[cmd.name] || cmd.name}`).then(async module => {
|
import(`./${alias[cmd.name] || cmd.name}`).then(async module => {
|
||||||
await module.default(cmd);
|
await module.default(cmd);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@ -43,12 +54,5 @@ export default class Interface {
|
|||||||
}
|
}
|
||||||
c.error(err);
|
c.error(err);
|
||||||
});
|
});
|
||||||
Interface.start();
|
|
||||||
});
|
|
||||||
|
|
||||||
Interface.rl.on('close', () => {
|
|
||||||
console.log('Have a great day!');
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,6 +6,7 @@
|
|||||||
import Interface from "./commands/Interface";
|
import Interface from "./commands/Interface";
|
||||||
import HttpServer from "./http/HttpServer";
|
import HttpServer from "./http/HttpServer";
|
||||||
import SRServer from "./server/kcp/SRServer";
|
import SRServer from "./server/kcp/SRServer";
|
||||||
|
import RCONServer from "./server/rcon/RCONServer";
|
||||||
import Banners from "./util/Banner";
|
import Banners from "./util/Banner";
|
||||||
import Logger from "./util/Logger";
|
import Logger from "./util/Logger";
|
||||||
import ProtoFactory from "./util/ProtoFactory"
|
import ProtoFactory from "./util/ProtoFactory"
|
||||||
@ -18,3 +19,4 @@ ProtoFactory.init();
|
|||||||
Interface.start();
|
Interface.start();
|
||||||
HttpServer.getInstance().start();
|
HttpServer.getInstance().start();
|
||||||
SRServer.getInstance().start();
|
SRServer.getInstance().start();
|
||||||
|
RCONServer.getInstance().start();
|
54
src/server/rcon/RCONServer.ts
Normal file
54
src/server/rcon/RCONServer.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// @ts-ignore
|
||||||
|
import { RCONServer as RServer } from "rcon-server";
|
||||||
|
import { Writable } from "stream";
|
||||||
|
import Interface, { Command } from "../../commands/Interface";
|
||||||
|
import Config from "../../util/Config";
|
||||||
|
import Logger from "../../util/Logger";
|
||||||
|
const c = new Logger("RCON", "green");
|
||||||
|
|
||||||
|
export default class RCONServer {
|
||||||
|
private static _instance: RCONServer;
|
||||||
|
public RCON!: RServer;
|
||||||
|
|
||||||
|
private constructor() { }
|
||||||
|
|
||||||
|
public static getInstance(): RCONServer {
|
||||||
|
if (!this._instance) this._instance = new RCONServer();
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
if (!Config.RCON.RCON_ENABLED) return;
|
||||||
|
this.RCON = new RServer({
|
||||||
|
host: Config.HTTP.HTTP_HOST,
|
||||||
|
clientLimit: Config.RCON.RCON_CLIENT_LIMIT,
|
||||||
|
destroySocketOnLimitExceeded: false,
|
||||||
|
emitAdvancedEvents: false,
|
||||||
|
password: Config.RCON.RCON_PASSWORD,
|
||||||
|
port: Config.RCON.RCON_PORT
|
||||||
|
});
|
||||||
|
|
||||||
|
this.RCON.on("listening", () => {
|
||||||
|
c.log(`Listening on ${Config.RCON.RCON_PORT}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.RCON.on("commandRequest", (cmd: {
|
||||||
|
size: number,
|
||||||
|
id: number,
|
||||||
|
type: number,
|
||||||
|
body: string
|
||||||
|
resolve: (value: string) => void,
|
||||||
|
}) => {
|
||||||
|
c.verbL(cmd);
|
||||||
|
Interface.handle(new Command(cmd.body));
|
||||||
|
cmd.resolve(`Command executed.`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.RCON.on("login", ({ pw, fail }: { pw: string, fail: boolean }) => {
|
||||||
|
c.debug(pw);
|
||||||
|
fail ? c.log(`Login failed`) : c.log(`Login successful`); // For some reason succ is flipped
|
||||||
|
});
|
||||||
|
|
||||||
|
this.RCON.connect();
|
||||||
|
}
|
||||||
|
}
|
263
src/server/rcon/rcon-server.d.ts
vendored
Normal file
263
src/server/rcon/rcon-server.d.ts
vendored
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
/** Declaration file generated by dts-gen */
|
||||||
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
|
declare module "rcon-server" {
|
||||||
|
export class RCONServer extends EventEmitter {
|
||||||
|
constructor(obj: {
|
||||||
|
port: number = 3839,
|
||||||
|
host: string = "127.0.0.1",
|
||||||
|
password: string = "password",
|
||||||
|
clientLimit: number = 1,
|
||||||
|
destroySocketOnLimitExceeded: boolean = true,
|
||||||
|
emitAdvancedEvents: boolean = false
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(...args: any[]): void;
|
||||||
|
|
||||||
|
getConnectedSockets(...args: any[]): void;
|
||||||
|
|
||||||
|
getServerSettings(...args: any[]): void;
|
||||||
|
|
||||||
|
getSocketServer(...args: any[]): void;
|
||||||
|
|
||||||
|
static captureRejectionSymbol: any;
|
||||||
|
|
||||||
|
static captureRejections: boolean;
|
||||||
|
|
||||||
|
static defaultMaxListeners: number;
|
||||||
|
|
||||||
|
static errorMonitor: any;
|
||||||
|
|
||||||
|
static getEventListeners(emitterOrTarget: any, type: any): any;
|
||||||
|
|
||||||
|
static init(opts: any): void;
|
||||||
|
|
||||||
|
static kMaxEventTargetListeners: any;
|
||||||
|
|
||||||
|
static kMaxEventTargetListenersWarned: any;
|
||||||
|
|
||||||
|
static listenerCount(emitter: any, type: any): any;
|
||||||
|
|
||||||
|
static on(emitter: any, event: any, options: any): any;
|
||||||
|
|
||||||
|
static once(emitter: any, name: any, options: any): any;
|
||||||
|
|
||||||
|
static setMaxListeners(n: any, eventTargets: any): void;
|
||||||
|
|
||||||
|
static usingDomains: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace RCONServer {
|
||||||
|
class EventEmitter {
|
||||||
|
constructor(opts: any);
|
||||||
|
|
||||||
|
addListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
emit(type: any, args: any): any;
|
||||||
|
|
||||||
|
eventNames(): any;
|
||||||
|
|
||||||
|
getMaxListeners(): any;
|
||||||
|
|
||||||
|
listenerCount(type: any): any;
|
||||||
|
|
||||||
|
listeners(type: any): any;
|
||||||
|
|
||||||
|
off(type: any, listener: any): any;
|
||||||
|
|
||||||
|
on(type: any, listener: any): any;
|
||||||
|
|
||||||
|
once(type: any, listener: any): any;
|
||||||
|
|
||||||
|
prependListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
prependOnceListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
rawListeners(type: any): any;
|
||||||
|
|
||||||
|
removeAllListeners(type: any, ...args: any[]): any;
|
||||||
|
|
||||||
|
removeListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
setMaxListeners(n: any): any;
|
||||||
|
|
||||||
|
static EventEmitter: any;
|
||||||
|
|
||||||
|
static captureRejectionSymbol: any;
|
||||||
|
|
||||||
|
static captureRejections: boolean;
|
||||||
|
|
||||||
|
static defaultMaxListeners: number;
|
||||||
|
|
||||||
|
static errorMonitor: any;
|
||||||
|
|
||||||
|
static getEventListeners(emitterOrTarget: any, type: any): any;
|
||||||
|
|
||||||
|
static init(opts: any): void;
|
||||||
|
|
||||||
|
static kMaxEventTargetListeners: any;
|
||||||
|
|
||||||
|
static kMaxEventTargetListenersWarned: any;
|
||||||
|
|
||||||
|
static listenerCount(emitter: any, type: any): any;
|
||||||
|
|
||||||
|
static on(emitter: any, event: any, options: any): any;
|
||||||
|
|
||||||
|
static once(emitter: any, name: any, options: any): any;
|
||||||
|
|
||||||
|
static setMaxListeners(n: any, eventTargets: any): void;
|
||||||
|
|
||||||
|
static usingDomains: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventEmitterAsyncResource {
|
||||||
|
constructor(...args: any[]);
|
||||||
|
|
||||||
|
emit(...args: any[]): void;
|
||||||
|
|
||||||
|
emitDestroy(...args: any[]): void;
|
||||||
|
|
||||||
|
static EventEmitterAsyncResource: any;
|
||||||
|
|
||||||
|
static captureRejectionSymbol: any;
|
||||||
|
|
||||||
|
static captureRejections: boolean;
|
||||||
|
|
||||||
|
static defaultMaxListeners: number;
|
||||||
|
|
||||||
|
static errorMonitor: any;
|
||||||
|
|
||||||
|
static getEventListeners(emitterOrTarget: any, type: any): any;
|
||||||
|
|
||||||
|
static init(opts: any): void;
|
||||||
|
|
||||||
|
static kMaxEventTargetListeners: any;
|
||||||
|
|
||||||
|
static kMaxEventTargetListenersWarned: any;
|
||||||
|
|
||||||
|
static listenerCount(emitter: any, type: any): any;
|
||||||
|
|
||||||
|
static on(emitter: any, event: any, options: any): any;
|
||||||
|
|
||||||
|
static once(emitter: any, name: any, options: any): any;
|
||||||
|
|
||||||
|
static setMaxListeners(n: any, eventTargets: any): void;
|
||||||
|
|
||||||
|
static usingDomains: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace EventEmitter {
|
||||||
|
class EventEmitterAsyncResource {
|
||||||
|
constructor(...args: any[]);
|
||||||
|
|
||||||
|
emit(...args: any[]): void;
|
||||||
|
|
||||||
|
emitDestroy(...args: any[]): void;
|
||||||
|
|
||||||
|
static EventEmitter: any;
|
||||||
|
|
||||||
|
static EventEmitterAsyncResource: any;
|
||||||
|
|
||||||
|
static captureRejectionSymbol: any;
|
||||||
|
|
||||||
|
static captureRejections: boolean;
|
||||||
|
|
||||||
|
static defaultMaxListeners: number;
|
||||||
|
|
||||||
|
static errorMonitor: any;
|
||||||
|
|
||||||
|
static getEventListeners(emitterOrTarget: any, type: any): any;
|
||||||
|
|
||||||
|
static init(opts: any): void;
|
||||||
|
|
||||||
|
static kMaxEventTargetListeners: any;
|
||||||
|
|
||||||
|
static kMaxEventTargetListenersWarned: any;
|
||||||
|
|
||||||
|
static listenerCount(emitter: any, type: any): any;
|
||||||
|
|
||||||
|
static on(emitter: any, event: any, options: any): any;
|
||||||
|
|
||||||
|
static once(emitter: any, name: any, options: any): any;
|
||||||
|
|
||||||
|
static setMaxListeners(n: any, eventTargets: any): void;
|
||||||
|
|
||||||
|
static usingDomains: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace EventEmitterAsyncResource {
|
||||||
|
class EventEmitter {
|
||||||
|
constructor(opts: any);
|
||||||
|
|
||||||
|
addListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
emit(type: any, args: any): any;
|
||||||
|
|
||||||
|
eventNames(): any;
|
||||||
|
|
||||||
|
getMaxListeners(): any;
|
||||||
|
|
||||||
|
listenerCount(type: any): any;
|
||||||
|
|
||||||
|
listeners(type: any): any;
|
||||||
|
|
||||||
|
off(type: any, listener: any): any;
|
||||||
|
|
||||||
|
on(type: any, listener: any): any;
|
||||||
|
|
||||||
|
once(type: any, listener: any): any;
|
||||||
|
|
||||||
|
prependListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
prependOnceListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
rawListeners(type: any): any;
|
||||||
|
|
||||||
|
removeAllListeners(type: any, ...args: any[]): any;
|
||||||
|
|
||||||
|
removeListener(type: any, listener: any): any;
|
||||||
|
|
||||||
|
setMaxListeners(n: any): any;
|
||||||
|
|
||||||
|
static EventEmitter: any;
|
||||||
|
|
||||||
|
static EventEmitterAsyncResource: any;
|
||||||
|
|
||||||
|
static captureRejectionSymbol: any;
|
||||||
|
|
||||||
|
static captureRejections: boolean;
|
||||||
|
|
||||||
|
static defaultMaxListeners: number;
|
||||||
|
|
||||||
|
static errorMonitor: any;
|
||||||
|
|
||||||
|
static getEventListeners(emitterOrTarget: any, type: any): any;
|
||||||
|
|
||||||
|
static init(opts: any): void;
|
||||||
|
|
||||||
|
static kMaxEventTargetListeners: any;
|
||||||
|
|
||||||
|
static kMaxEventTargetListenersWarned: any;
|
||||||
|
|
||||||
|
static listenerCount(emitter: any, type: any): any;
|
||||||
|
|
||||||
|
static on(emitter: any, event: any, options: any): any;
|
||||||
|
|
||||||
|
static once(emitter: any, name: any, options: any): any;
|
||||||
|
|
||||||
|
static setMaxListeners(n: any, eventTargets: any): void;
|
||||||
|
|
||||||
|
static usingDomains: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -28,6 +28,12 @@ const DEFAULT_CONFIG = {
|
|||||||
MAINTENANCE: false,
|
MAINTENANCE: false,
|
||||||
MAINTENANCE_MSG: "Server is in maintenance mode."
|
MAINTENANCE_MSG: "Server is in maintenance mode."
|
||||||
},
|
},
|
||||||
|
RCON: {
|
||||||
|
RCON_ENABLED: false,
|
||||||
|
RCON_PASSWORD: "password",
|
||||||
|
RCON_PORT: 22103,
|
||||||
|
RCON_CLIENT_LIMIT: 1
|
||||||
|
},
|
||||||
AUTO_ACCOUNT: false
|
AUTO_ACCOUNT: false
|
||||||
}
|
}
|
||||||
type DefaultConfig = typeof DEFAULT_CONFIG;
|
type DefaultConfig = typeof DEFAULT_CONFIG;
|
||||||
@ -82,6 +88,12 @@ export default class Config {
|
|||||||
MAINTENANCE_MSG: string;
|
MAINTENANCE_MSG: string;
|
||||||
} = Config.config.GAMESERVER;
|
} = Config.config.GAMESERVER;
|
||||||
public static AUTO_ACCOUNT: boolean = Config.config.AUTO_ACCOUNT;
|
public static AUTO_ACCOUNT: boolean = Config.config.AUTO_ACCOUNT;
|
||||||
|
public static RCON: {
|
||||||
|
RCON_ENABLED: boolean;
|
||||||
|
RCON_PASSWORD: string;
|
||||||
|
RCON_PORT: number;
|
||||||
|
RCON_CLIENT_LIMIT: number;
|
||||||
|
} = Config.config.RCON;
|
||||||
|
|
||||||
private constructor() { }
|
private constructor() { }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user