diff --git a/app.js b/app.js index 6e6d637..071859f 100644 --- a/app.js +++ b/app.js @@ -440,13 +440,12 @@ function startAutoRefresh() { document.getElementById('refresh-timer').textContent = '● Live'; document.getElementById('refresh-timer').style.color = '#4ade80'; - async function poll() { - while (true) { + const myId = ++pollId; + (async function poll() { + while (pollId === myId) { await loadPGN(false); - await new Promise(r => setTimeout(r, 30000)); } - } - poll(); + })(); } /** @@ -470,7 +469,7 @@ function hideError() { */ document.getElementById('refresh-btn').addEventListener('click', () => { pollId++; - loadPGN(true); + loadPGN(true).then(() => startAutoRefresh()); }); /** diff --git a/server.py b/server.py index 0e2a8d8..8be7dda 100644 --- a/server.py +++ b/server.py @@ -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():