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(() => {}); } }