import { parseStatus, runRcon } from './rcon.js'; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); /** * Gemeinsamer Konfigurationsablauf für echte Server per RCON: * Befehle vor dem Mapwechsel senden, warten bis die Map geladen ist, dann Match-Einstellungen setzen. */ export async function configureViaRcon(target, plan, { loadTimeoutMs = 120_000, pollMs = 3000 } = {}) { try { await runRcon(target, plan.beforeMapChange); } catch (err) { // Beim changelevel trennt der Server die RCON-Verbindung teilweise – das ist kein Fehler. if (!/geschlossen/.test(err.message)) throw new Error(`Befehle konnten nicht gesendet werden: ${err.message}`); } const deadline = Date.now() + loadTimeoutMs; let lastError = null; for (;;) { await sleep(pollMs); try { const [status] = await runRcon(target, ['status']); const parsed = parseStatus(status); if (parsed.map === plan.map || (!parsed.map && status.includes(plan.map))) break; lastError = `aktuell geladen: ${parsed.map ?? 'unbekannt'}`; } catch (err) { lastError = err.message; } if (Date.now() > deadline) { throw new Error(`Map ${plan.map} wurde nicht rechtzeitig geladen (${lastError ?? 'keine Antwort'})`); } } try { await runRcon(target, plan.afterMapChange); } catch (err) { throw new Error(`Match-Einstellungen konnten nicht gesetzt werden: ${err.message}`); } } export async function rconStatus(target) { const [output] = await runRcon(target, ['status'], { timeoutMs: 4000 }); return parseStatus(output); }