Files
lara-schach-live/lara-chess/server.py
2026-05-24 14:19:01 +02:00

169 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Lokal Proxy-Server für Lara's Schachturnier
Lädt die PGN-Datei und stellt sie mit CORS-Headern bereit.
"""
import http.server
import socketserver
import urllib.request
import sys
import os
import threading
import time
from datetime import datetime
PGN_URL = "https://www.deutsche-schachjugend.de/2026/odjm-d/partien/gesamt-utf8.pgn"
PORT = 8111
CACHE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache")
CACHE_FILE = os.path.join(CACHE_DIR, "gesamt-utf8.pgn")
CACHE_TTL = 30 # Sekunden
os.makedirs(CACHE_DIR, exist_ok=True)
def fetch_pgn():
"""Lädt die PGN-Datei von der URL als Bytes."""
try:
req = urllib.request.Request(PGN_URL, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(req, timeout=30) as response:
return response.read()
except Exception as e:
print(f"[{datetime.now().strftime('%H:%M:%S')}] Fehler beim Laden: {e}")
return None
def get_pgn_content():
"""Gibt PGN-Inhalt als Bytes zurück, nutzt Cache wenn möglich."""
now = time.time()
# Prüfe Cache
if os.path.exists(CACHE_FILE):
age = now - os.path.getmtime(CACHE_FILE)
if age < CACHE_TTL:
with open(CACHE_FILE, "rb") as f:
return f.read()
# Cache verfallen oder nicht vorhanden -> neu laden
content = fetch_pgn()
if content:
with open(CACHE_FILE, "wb") as f:
f.write(content)
print(f"[{datetime.now().strftime('%H:%M:%S')}] PGN aktualisiert ({len(content)} Bytes)")
return content
# Fallback: alter Cache
if os.path.exists(CACHE_FILE):
print(f"[{datetime.now().strftime('%H:%M:%S')}] Verwende alten Cache")
with open(CACHE_FILE, "rb") as f:
return f.read()
return None
class PGNHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/pgn":
content = get_pgn_content()
if content:
self.send_response(200)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Cache-Control", "no-cache")
self.end_headers()
self.wfile.write(content)
else:
self.send_response(502)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
self.wfile.write(b'{"error": "Konnte PGN nicht laden"}')
elif self.path == "/status":
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
self.wfile.write(b'{"status": "ok"}')
else:
# Statische Dateien aus dem Verzeichnis
if self.path == "/":
self.path = "/index.html"
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), self.path.lstrip("/"))
if os.path.isfile(filepath):
content_types = {
".html": "text/html",
".css": "text/css",
".js": "application/javascript",
".json": "application/json",
".png": "image/png",
".jpg": "image/jpeg",
".svg": "image/svg+xml",
}
ext = os.path.splitext(filepath)[1]
content_type = content_types.get(ext, "application/octet-stream")
with open(filepath, "rb") as f:
content = f.read()
self.send_response(200)
self.send_header("Content-Type", f"{content_type}; charset=utf-8")
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
self.wfile.write(content)
else:
self.send_response(404)
self.end_headers()
def log_message(self, format, *args):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {args[0]}")
def background_refresh():
"""Aktualisiert den Cache im Hintergrund."""
while True:
time.sleep(CACHE_TTL)
try:
content = fetch_pgn()
if content:
with open(CACHE_FILE, "wb") as f:
f.write(content)
except Exception as e:
print(f"[{datetime.now().strftime('%H:%M:%S')}] Hintergrund-Refresh Fehler: {e}")
def main():
print("=" * 50)
print(" [TROPHY] Lara Kiesewetter Live Schachturnier")
print("=" * 50)
print(f" Server läuft auf: http://localhost:{PORT}")
print(f" Drücke Ctrl+C zum Beenden")
print("=" * 50)
# Initialer Ladeversuch
content = fetch_pgn()
if content:
with open(CACHE_FILE, "wb") as f:
f.write(content)
print(f"[OK] PGN geladen ({len(content)} Bytes)")
else:
print("[WARN] Initialer Ladeversuch fehlgeschlagen, wird wiederholt...")
# Hintergrund-Refresh Thread starten
refresh_thread = threading.Thread(target=background_refresh, daemon=True)
refresh_thread.start()
# Server starten
with socketserver.TCPServer(("", PORT), PGNHandler) as httpd:
print(f"\n[SERVER] Server gestartet: http://localhost:{PORT}\n")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\n[BYE] Server gestoppt.")
if __name__ == "__main__":
main()