update
This commit is contained in:
78
server/matchmaker.py
Normal file
78
server/matchmaker.py
Normal 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"]}
|
||||
Reference in New Issue
Block a user