add tss tournament stuff (#1348)

This commit is contained in:
NotSoToothless
2026-06-20 21:25:08 -07:00
committed by GitHub
parent 2f4ae54bdb
commit da66722e03
3 changed files with 130 additions and 12 deletions
+57 -8
View File
@@ -17,15 +17,17 @@ the captured sample payloads.
from __future__ import annotations
import asyncio
from concurrent.futures import ThreadPoolExecutor, as_completed
import json
import logging
import os
import sqlite3
import threading
import time
import urllib.parse
import urllib.request
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, List, Optional, Tuple
from BOT.storage import STORAGE_DIR
@@ -36,6 +38,7 @@ TSS_TOURNAMENTS_DB_PATH: Path = STORAGE_DIR / "tss_tournaments.db"
_API_URL = "https://tss.warthunder.com/functions.php"
_API_HEADERS = {"Content-Type": "application/x-www-form-urlencoded"}
_API_TIMEOUT = 20
_DEFAULT_BATTLE_WORKERS = max(1, int(os.environ.get("TSS_TOURNAMENT_BATTLE_WORKERS", "8")))
# Re-scan a live tournament at most this often; stop re-scanning this long after
# its end time (battle rows land shortly after a game finishes).
@@ -521,6 +524,8 @@ def build_scan_sync(
fallback_name: Optional[str] = None,
active_meta: Optional[Dict[str, Any]] = None,
now: Optional[int] = None,
battle_workers: int = _DEFAULT_BATTLE_WORKERS,
progress: Optional[Callable[[str], None]] = None,
) -> Dict[str, Any]:
"""Fetch + assemble the full authoritative structure for one tournament.
@@ -563,19 +568,23 @@ def build_scan_sync(
# Battles per match → session links. Dedupe match_ids (same id can repeat
# across sources); fetch once per (match_id, type_bracket).
battles: List[Dict[str, Any]] = []
battle_targets: List[Dict[str, Any]] = []
seen_battle_keys = set()
for match in matches:
mid, tb = match["match_id"], match["type_bracket"]
if not mid or (mid, tb) in seen_battle_keys:
continue
seen_battle_keys.add((mid, tb))
rows = _request("GET", "getListAllBattles", tournamentID=tournament_id, idMatch=mid, typeBracket=tb)
fill_names_from_battles(match, rows)
match_battles, technical = parse_battles(rows, tournament_id, mid, tb)
if technical and match["status"] in ("pending", "bye"):
match["status"] = "technical"
battles.extend(match_battles)
battle_targets.append(match)
if progress:
progress(f"{len(matches)} matches; fetching battles for {len(battle_targets)} match rows")
battles = fetch_battles_for_matches(
tournament_id,
battle_targets,
workers=max(1, battle_workers),
progress=progress,
)
type_set = {m["type_bracket"] for m in matches}
meta = active_meta or {}
@@ -601,6 +610,46 @@ def build_scan_sync(
}
def fetch_battles_for_matches(
tournament_id: int,
matches: List[Dict[str, Any]],
*,
workers: int = _DEFAULT_BATTLE_WORKERS,
progress: Optional[Callable[[str], None]] = None,
) -> List[Dict[str, Any]]:
"""Fetch getListAllBattles rows for each match concurrently."""
if not matches:
return []
def one(match: Dict[str, Any]) -> Tuple[Dict[str, Any], Any, List[Dict[str, Any]], bool]:
mid, tb = match["match_id"], match["type_bracket"]
rows = _request(
"GET",
"getListAllBattles",
tournamentID=tournament_id,
idMatch=mid,
typeBracket=tb,
)
match_battles, technical = parse_battles(rows, tournament_id, mid, tb)
return match, rows, match_battles, technical
battles: List[Dict[str, Any]] = []
done = 0
total = len(matches)
with ThreadPoolExecutor(max_workers=max(1, workers)) as pool:
futures = [pool.submit(one, match) for match in matches]
for future in as_completed(futures):
match, rows, match_battles, technical = future.result()
fill_names_from_battles(match, rows)
if technical and match["status"] in ("pending", "bye"):
match["status"] = "technical"
battles.extend(match_battles)
done += 1
if progress and (done == total or done % 25 == 0):
progress(f"battle lookups {done}/{total}")
return battles
# ---------------------------------------------------------------------------
# Storage
# ---------------------------------------------------------------------------