-am (#1333)
This commit is contained in:
+27
-5
@@ -27,11 +27,11 @@ CREATE TABLE IF NOT EXISTS match_logs (
|
|||||||
session_id TEXT PRIMARY KEY,
|
session_id TEXT PRIMARY KEY,
|
||||||
chat_log_json TEXT,
|
chat_log_json TEXT,
|
||||||
battle_log_json TEXT,
|
battle_log_json TEXT,
|
||||||
|
event_log_json TEXT,
|
||||||
built_unix INTEGER
|
built_unix INTEGER
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _fmt_time(ms: int) -> str:
|
def _fmt_time(ms: int) -> str:
|
||||||
total_s = int(ms) // 1000
|
total_s = int(ms) // 1000
|
||||||
return f"{total_s // 60:02d}:{total_s % 60:02d}"
|
return f"{total_s // 60:02d}:{total_s % 60:02d}"
|
||||||
@@ -49,6 +49,17 @@ def _decompress_events(raw_events: Any) -> dict:
|
|||||||
return raw_events or {}
|
return raw_events or {}
|
||||||
|
|
||||||
|
|
||||||
|
def build_event_log(game: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""Return the raw event slices the website needs for per-unit state."""
|
||||||
|
events = _decompress_events(game.get("events", {}))
|
||||||
|
if not isinstance(events, dict):
|
||||||
|
return {"kills": [], "damage": []}
|
||||||
|
return {
|
||||||
|
"kills": list(events.get("kills") or []),
|
||||||
|
"damage": list(events.get("damage") or []),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _strip_tag(tag: str) -> str:
|
def _strip_tag(tag: str) -> str:
|
||||||
s = (tag or "").strip()
|
s = (tag or "").strip()
|
||||||
if len(s) >= 3 and not s[0].isalnum() and not s[-1].isalnum():
|
if len(s) >= 3 and not s[0].isalnum() and not s[-1].isalnum():
|
||||||
@@ -166,19 +177,30 @@ def build_match_logs(game: dict[str, Any]) -> tuple[list[str], list[str]]:
|
|||||||
|
|
||||||
|
|
||||||
async def upsert_match_logs(
|
async def upsert_match_logs(
|
||||||
db_path, session_id: str, chat_log: list[str], battle_log: list[str]
|
db_path,
|
||||||
|
session_id: str,
|
||||||
|
chat_log: list[str],
|
||||||
|
battle_log: list[str],
|
||||||
|
event_log: dict[str, Any] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
import time
|
import time
|
||||||
async with aiosqlite.connect(db_path) as conn:
|
async with aiosqlite.connect(db_path) as conn:
|
||||||
await conn.execute(MATCH_LOGS_SQL)
|
await conn.execute(MATCH_LOGS_SQL)
|
||||||
|
try:
|
||||||
|
await conn.execute("ALTER TABLE match_logs ADD COLUMN event_log_json TEXT")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
await conn.execute(
|
await conn.execute(
|
||||||
"""INSERT INTO match_logs (session_id, chat_log_json, battle_log_json, built_unix)
|
"""INSERT INTO match_logs (session_id, chat_log_json, battle_log_json, event_log_json, built_unix)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?)
|
||||||
ON CONFLICT(session_id) DO UPDATE SET
|
ON CONFLICT(session_id) DO UPDATE SET
|
||||||
chat_log_json=excluded.chat_log_json,
|
chat_log_json=excluded.chat_log_json,
|
||||||
battle_log_json=excluded.battle_log_json,
|
battle_log_json=excluded.battle_log_json,
|
||||||
|
event_log_json=excluded.event_log_json,
|
||||||
built_unix=excluded.built_unix""",
|
built_unix=excluded.built_unix""",
|
||||||
(str(session_id), json.dumps(chat_log, ensure_ascii=False),
|
(str(session_id), json.dumps(chat_log, ensure_ascii=False),
|
||||||
json.dumps(battle_log, ensure_ascii=False), int(time.time())),
|
json.dumps(battle_log, ensure_ascii=False),
|
||||||
|
json.dumps(event_log or {"kills": [], "damage": []}, ensure_ascii=False),
|
||||||
|
int(time.time())),
|
||||||
)
|
)
|
||||||
await conn.commit()
|
await conn.commit()
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ROOT = pathlib.Path(__file__).resolve().parents[1]
|
|||||||
sys.path.insert(0, str(ROOT))
|
sys.path.insert(0, str(ROOT))
|
||||||
sys.path.insert(0, str(ROOT.parent / "SHARED"))
|
sys.path.insert(0, str(ROOT.parent / "SHARED"))
|
||||||
|
|
||||||
from BOT.match_logs import build_match_logs, upsert_match_logs, MATCH_LOGS_SQL
|
from BOT.match_logs import build_event_log, build_match_logs, upsert_match_logs, MATCH_LOGS_SQL
|
||||||
from BOT.storage import TSS_BATTLES_DB_PATH
|
from BOT.storage import TSS_BATTLES_DB_PATH
|
||||||
|
|
||||||
REPLAYS = pathlib.Path(os.environ["STORAGE_VOL_PATH"]) / "REPLAYS" / "TSS"
|
REPLAYS = pathlib.Path(os.environ["STORAGE_VOL_PATH"]) / "REPLAYS" / "TSS"
|
||||||
@@ -36,10 +36,11 @@ async def main(dry_run: bool) -> None:
|
|||||||
print(f" skip {sid}: {exc}")
|
print(f" skip {sid}: {exc}")
|
||||||
continue
|
continue
|
||||||
chat, battle = build_match_logs(game)
|
chat, battle = build_match_logs(game)
|
||||||
|
event_log = build_event_log(game)
|
||||||
if dry_run:
|
if dry_run:
|
||||||
print(f" {sid}: chat={len(chat)} battle={len(battle)}")
|
print(f" {sid}: chat={len(chat)} battle={len(battle)} kills={len(event_log.get('kills') or [])}")
|
||||||
else:
|
else:
|
||||||
await upsert_match_logs(TSS_BATTLES_DB_PATH, sid, chat, battle)
|
await upsert_match_logs(TSS_BATTLES_DB_PATH, sid, chat, battle, event_log)
|
||||||
done += 1
|
done += 1
|
||||||
print(f"{'Would backfill' if dry_run else 'Backfilled'} "
|
print(f"{'Would backfill' if dry_run else 'Backfilled'} "
|
||||||
f"{len(files) if dry_run else done} sessions")
|
f"{len(files) if dry_run else done} sessions")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import pathlib
|
|||||||
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
|
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
|
||||||
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "SHARED"))
|
sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "SHARED"))
|
||||||
|
|
||||||
from BOT.match_logs import build_match_logs
|
from BOT.match_logs import build_event_log, build_match_logs
|
||||||
|
|
||||||
|
|
||||||
def _game():
|
def _game():
|
||||||
@@ -53,8 +53,15 @@ def test_events_base85_zstd_compressed():
|
|||||||
assert battle and "destroyed" in battle[0]
|
assert battle and "destroyed" in battle[0]
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_log_preserves_kill_victim_unit():
|
||||||
|
event_log = build_event_log(_game())
|
||||||
|
assert event_log["kills"][0]["offended_uid"] == 2
|
||||||
|
assert event_log["kills"][0]["offended_unit"] == "germ_pz_iv"
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_chat_log_format()
|
test_chat_log_format()
|
||||||
test_battle_log_kill_prefix_and_text()
|
test_battle_log_kill_prefix_and_text()
|
||||||
test_events_base85_zstd_compressed()
|
test_events_base85_zstd_compressed()
|
||||||
|
test_event_log_preserves_kill_victim_unit()
|
||||||
print("ALL TESTS PASSED")
|
print("ALL TESTS PASSED")
|
||||||
|
|||||||
@@ -164,10 +164,10 @@ async def _handle_game(game: Dict[str, Any]) -> None:
|
|||||||
await insert_match(game)
|
await insert_match(game)
|
||||||
await insert_player_games(game)
|
await insert_player_games(game)
|
||||||
await upsert_tss_teams(game)
|
await upsert_tss_teams(game)
|
||||||
from BOT.match_logs import build_match_logs, upsert_match_logs
|
from BOT.match_logs import build_event_log, build_match_logs, upsert_match_logs
|
||||||
from BOT.storage import TSS_BATTLES_DB_PATH
|
from BOT.storage import TSS_BATTLES_DB_PATH
|
||||||
chat_log, battle_log = build_match_logs(game)
|
chat_log, battle_log = build_match_logs(game)
|
||||||
await upsert_match_logs(TSS_BATTLES_DB_PATH, sid, chat_log, battle_log)
|
await upsert_match_logs(TSS_BATTLES_DB_PATH, sid, chat_log, battle_log, build_event_log(game))
|
||||||
log.info("Stored game %s in DB", sid)
|
log.info("Stored game %s in DB", sid)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.error("DB insert failed for %s: %s", sid, exc)
|
log.error("DB insert failed for %s: %s", sid, exc)
|
||||||
|
|||||||
Reference in New Issue
Block a user