Server: If-Modified-Since, block bis Änderung; Client: sofortiger Re-Poll

This commit is contained in:
2026-05-24 15:34:27 +02:00
parent 7efa38c91a
commit ab4486cc98
2 changed files with 27 additions and 29 deletions

View File

@@ -8,6 +8,7 @@ import http.server
import socketserver
import urllib.request
import urllib.parse
import urllib.error
import sys
import os
import threading
@@ -31,28 +32,33 @@ last_standings_fetch_time = None
def fetch_pgn():
"""Lädt die PGN-Datei von der URL als Bytes."""
"""Lädt die PGN-Datei von der URL als Bytes.
Nutzt If-Modified-Since gibt (data, changed) zurück.
changed=False bedeutet 304 Not Modified (keine neuen Daten)."""
global last_fetch_time
try:
headers = {"User-Agent": "Mozilla/5.0"}
if last_fetch_time:
headers["modified_since"] = str(last_fetch_time)
headers["If-Modified-Since"] = datetime.utcfromtimestamp(last_fetch_time).strftime("%a, %d %b %Y %H:%M:%S GMT")
req = urllib.request.Request(PGN_URL, headers=headers)
with urllib.request.urlopen(req, timeout=31) as response:
data = response.read()
last_fetch_time = time.time()
return data
return data, True
except urllib.error.HTTPError as e:
if e.code == 304:
return None, False
print(f"[{datetime.now().strftime('%H:%M:%S')}] HTTP-Fehler: {e}")
return None, False
except Exception as e:
print(f"[{datetime.now().strftime('%H:%M:%S')}] Fehler beim Laden: {e}")
return None
return None, False
def get_pgn_content_longpoll(since=0):
"""Long-Poll: Gibt PGN-Inhalt + mtime zurück.
Wenn Cache seit `since` unverändert ist, wird bis zu 31s gewartet."""
deadline = time.time() + 31
while time.time() < deadline:
"""Long-Poll: Blockiert, bis sich die PGN-Datei tatsächlich ändert.
Antwortet nur bei neuen Daten, nie mit unverändertem Stand."""
while True:
if os.path.exists(CACHE_FILE):
mtime = os.path.getmtime(CACHE_FILE)
if mtime > since:
@@ -60,28 +66,21 @@ def get_pgn_content_longpoll(since=0):
return f.read(), mtime
age = time.time() - mtime
if age >= CACHE_TTL:
content = fetch_pgn()
if content:
content, changed = fetch_pgn()
if changed and content is not None:
with open(CACHE_FILE, "wb") as f:
f.write(content)
new_mtime = os.path.getmtime(CACHE_FILE)
if new_mtime > since:
print(f"[{datetime.now().strftime('%H:%M:%S')}] PGN via Long-Poll aktualisiert ({len(content)} Bytes)")
return content, new_mtime
print(f"[{datetime.now().strftime('%H:%M:%S')}] PGN via Long-Poll aktualisiert ({len(content)} Bytes)")
return content, new_mtime
else:
content = fetch_pgn()
if content:
content, changed = fetch_pgn()
if changed and content is not None:
with open(CACHE_FILE, "wb") as f:
f.write(content)
return content, os.path.getmtime(CACHE_FILE)
time.sleep(2)
# Timeout aktuellen Stand zurückgeben
if os.path.exists(CACHE_FILE):
with open(CACHE_FILE, "rb") as f:
return f.read(), os.path.getmtime(CACHE_FILE)
return None, 0
time.sleep(5)
def fetch_standings():