This commit is contained in:
team3
2026-09-07 17:38:17 +02:00
parent 6478559252
commit 2a9ab4c7da
11 changed files with 521 additions and 125 deletions

78
server/matchmaker.py Normal file
View File

@@ -0,0 +1,78 @@
"""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"]}