"""Räume verwalten: Code vergeben, headless Spielserver starten, aufräumen. Ein Raum ist ein eigener Godot-Prozess auf einem festen UDP-Port. Der Code zeigt nur auf diesen Port. Läuft der Prozess nicht mehr, ist der Code frei. """ import os import random import subprocess from pathlib import Path from fastapi import FastAPI, HTTPException # Ohne I, O, 0 und 1: die verwechselt man beim Vorlesen ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" CODE_LAENGE = 4 GODOT = os.getenv("GODOT", "godot") SPIEL_PFAD = Path(os.getenv("SPIEL_PFAD", "/app/spiel")) # Was die Clients als Adresse bekommen SPIEL_HOST = os.getenv("SPIEL_HOST", "pirate-dice.marha.de") PORT_VON = int(os.getenv("PORT_VON", "8911")) PORT_BIS = int(os.getenv("PORT_BIS", "8940")) app = FastAPI(title="Pirate Dice Matchmaker") ## code -> {"port": int, "proc": Popen} raeume: dict = {} def aufraeumen() -> None: """Beendete Räume vergessen. Godot beendet sich selbst, wenn es leer ist.""" for code in [c for c, r in raeume.items() if r["proc"].poll() is not None]: del raeume[code] def freier_port() -> int: belegt = {r["port"] for r in raeume.values()} for port in range(PORT_VON, PORT_BIS + 1): if port not in belegt: return port raise HTTPException(status_code=503, detail="Alle Räume belegt") def neuer_code() -> str: while True: code = "".join(random.choice(ALPHABET) for _ in range(CODE_LAENGE)) if code not in raeume: return code @app.get("/api/health") def health(): aufraeumen() return {"ok": True, "raeume": len(raeume)} @app.post("/api/raum") def raum_anlegen(): aufraeumen() port = freier_port() code = neuer_code() proc = subprocess.Popen( [GODOT, "--headless", "--path", str(SPIEL_PFAD), "--", "server", str(port)], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) raeume[code] = {"port": port, "proc": proc} return {"code": code, "host": SPIEL_HOST, "port": port} @app.get("/api/raum/{code}") def raum_suchen(code: str): aufraeumen() raum = raeume.get(code.strip().upper()) if not raum: raise HTTPException(status_code=404, detail="Code unbekannt") return {"code": code.upper(), "host": SPIEL_HOST, "port": raum["port"]}