Backend: Match-Lobbys, Map-Veto, Echtzeit und CS2-Serveradapter
Express + Socket.IO + SQLite. Veto-Engine mit konfigurierbaren Map-Pools und validierten Abläufen, rollenbasierte Berechtigungen, Server-Lebenszyklus mit Demo-, Docker- und Static-Pool-Adapter (RCON), automatisches Herunterfahren. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
104aa1a67b
27 files changed
+6355
No files matched your search
@@ -0,0 +1,56 @@
|
||||
import { configureViaRcon, rconStatus } from './rconConfigure.js';
|
||||
import { runRcon } from './rcon.js';
|
||||
|
||||
/**
|
||||
* Nutzt bereits laufende, selbst betriebene CS2-Server (CS2_STATIC_SERVERS).
|
||||
* "Start" bedeutet hier: einen freien Server aus dem Pool reservieren und per RCON prüfen.
|
||||
* "Stopp" gibt ihn wieder frei und setzt ein zufälliges Serverpasswort, damit niemand
|
||||
* mit alten Zugangsdaten auf dem Server bleibt. Der Prozess selbst wird nicht beendet.
|
||||
*/
|
||||
export class StaticPoolServerAdapter {
|
||||
constructor({ servers }, { getUsedPorts }) {
|
||||
this.name = 'static';
|
||||
this.simulated = false;
|
||||
this.servers = servers;
|
||||
this.getUsedPorts = getUsedPorts;
|
||||
if (!servers.length) throw new Error('SERVER_ADAPTER=static benötigt CS2_STATIC_SERVERS');
|
||||
}
|
||||
|
||||
async start() {
|
||||
const used = this.getUsedPorts();
|
||||
const free = this.servers.find((s) => !used.has(`${s.host}:${s.port}`));
|
||||
if (!free) throw new Error('Alle konfigurierten Server sind belegt');
|
||||
return {
|
||||
handle: { host: free.host, port: free.port, poolKey: `${free.host}:${free.port}`, rconPassword: free.rconPassword },
|
||||
host: free.host,
|
||||
port: free.port,
|
||||
tvPort: free.tvPort,
|
||||
};
|
||||
}
|
||||
|
||||
target(handle) {
|
||||
return { host: handle.host, port: handle.port, password: handle.rconPassword };
|
||||
}
|
||||
|
||||
async status(handle) {
|
||||
try {
|
||||
const status = await rconStatus(this.target(handle));
|
||||
return { state: 'running', playerCount: status.playerCount, map: status.map };
|
||||
} catch (err) {
|
||||
return { state: 'starting', message: `Server nicht erreichbar: ${err.message}` };
|
||||
}
|
||||
}
|
||||
|
||||
async configure(handle, plan) {
|
||||
await configureViaRcon(this.target(handle), plan);
|
||||
}
|
||||
|
||||
async sendCommands(handle, commands) {
|
||||
return runRcon(this.target(handle), commands);
|
||||
}
|
||||
|
||||
async stop(handle, { resetPassword } = {}) {
|
||||
if (!resetPassword) return;
|
||||
await runRcon(this.target(handle), [`sv_password "${resetPassword}"`, 'tv_stoprecord']).catch(() => {});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user