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:
SPP UserandClaude Opus 5.5 committed 2026-10-25 16:50:22 +01:00
commit 104aa1a67b
27 files changed
+6355

No files matched your search

+51
View File
@@ -0,0 +1,51 @@
// DEMO-ADAPTER: Es wird KEIN echter CS2-Server gestartet.
// Er simuliert nur Startdauer und Konfiguration, damit der Ablauf ohne Hosting getestet werden kann.
// Das Flag simulated=true sorgt dafür, dass das Frontend den Server ausdrücklich als Simulation kennzeichnet.
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export class DemoServerAdapter {
constructor({ startSeconds = 20, failFirstConfigure = false } = {}) {
this.name = 'demo';
this.simulated = true;
this.startMs = startSeconds * 1000;
this.failFirstConfigure = failFirstConfigure;
this.configureCalls = new Map();
}
async start({ matchId }) {
return {
handle: { demo: true, matchId, startedAt: Date.now() },
host: 'demo.invalid',
port: 27015,
tvPort: 27020,
};
}
async status(handle) {
if (handle.stopped) return { state: 'stopped', message: 'Simulation beendet' };
const elapsed = Date.now() - handle.startedAt;
if (elapsed < this.startMs) {
return { state: 'starting', message: `Simulierter Start (${Math.ceil((this.startMs - elapsed) / 1000)} s)` };
}
return { state: 'running', message: 'Simulation – kein echter Server', playerCount: null };
}
async configure(handle, plan) {
await sleep(1500);
const calls = (this.configureCalls.get(handle.matchId) ?? 0) + 1;
this.configureCalls.set(handle.matchId, calls);
if (this.failFirstConfigure && calls === 1) {
throw new Error('Simulierter Konfigurationsfehler (DEMO_FAIL_FIRST_CONFIGURE) – bitte erneut versuchen');
}
handle.map = plan.map;
}
async sendCommands(handle, commands) {
return commands.map(() => '(Demo – nicht ausgeführt)');
}
async stop(handle) {
handle.stopped = true;
}
}