From 1fbea7e70133c236a3f6a55321ab86485c0d6137 Mon Sep 17 00:00:00 2001 From: jerick Date: Wed, 28 Jan 2026 13:00:15 -0500 Subject: [PATCH] Enhanced logging --- routers/factions.py | 98 +++++++++++++++++++++++++++++++++++++++----- services/torn_api.py | 90 ++++++++++++++++++++++++---------------- 2 files changed, 141 insertions(+), 47 deletions(-) diff --git a/routers/factions.py b/routers/factions.py index 0785d4f..cc805a8 100644 --- a/routers/factions.py +++ b/routers/factions.py @@ -1,7 +1,7 @@ #Faction data population and status management endpoints. import json from pathlib import Path -from fastapi import APIRouter +from fastapi import APIRouter, Request, HTTPException from models import FactionRequest from services.server_state import STATE @@ -13,25 +13,101 @@ from services.torn_api import ( stop_friendly_status_loop, stop_enemy_status_loop ) +from services.activity_log import activity_logger from utils import load_json_list +from utils.auth import get_current_user router = APIRouter(prefix="/api", tags=["factions"]) @router.post("/populate_friendly") -async def api_populate_friendly(data: FactionRequest): - await populate_friendly(data.faction_id) - # Return members list for frontend (already in STATE from populate_friendly) - members = [m.model_dump() for m in STATE.friendly.values()] - return {"status": "friendly populated", "id": data.faction_id, "members": members} +async def api_populate_friendly(request: Request, data: FactionRequest): + # Get username for logging + try: + user_info = get_current_user(request) + username = user_info.get("username", "Unknown") + except: + username = "Unknown" + + try: + await activity_logger.log_action( + username, + "Populate Friendly", + f"Starting population for faction {data.faction_id}" + ) + + result = await populate_friendly(data.faction_id) + + if not result: + await activity_logger.log_action( + username, + "Populate Friendly Failed", + f"Failed to populate faction {data.faction_id} - API returned False (check API key, faction ID, or network)" + ) + raise HTTPException(status_code=500, detail="Failed to populate friendly faction - check logs") + + # Return members list for frontend (already in STATE from populate_friendly) + members = [m.model_dump() for m in STATE.friendly.values()] + + await activity_logger.log_action( + username, + "Populate Friendly Success", + f"Populated {len(members)} members from faction {data.faction_id}" + ) + + return {"status": "friendly populated", "id": data.faction_id, "members": members} + + except HTTPException: + raise + except Exception as e: + error_msg = f"Error populating friendly faction {data.faction_id}: {type(e).__name__}: {str(e)}" + await activity_logger.log_action(username, "Populate Friendly Error", error_msg) + raise HTTPException(status_code=500, detail=error_msg) @router.post("/populate_enemy") -async def api_populate_enemy(data: FactionRequest): - await populate_enemy(data.faction_id) - # Return members list for frontend (already in STATE from populate_enemy) - members = [m.model_dump() for m in STATE.enemy.values()] - return {"status": "enemy populated", "id": data.faction_id, "members": members} +async def api_populate_enemy(request: Request, data: FactionRequest): + # Get username for logging + try: + user_info = get_current_user(request) + username = user_info.get("username", "Unknown") + except: + username = "Unknown" + + try: + await activity_logger.log_action( + username, + "Populate Enemy", + f"Starting population for faction {data.faction_id}" + ) + + result = await populate_enemy(data.faction_id) + + if not result: + await activity_logger.log_action( + username, + "Populate Enemy Failed", + f"Failed to populate faction {data.faction_id} - API returned False (check API key, faction ID, or network)" + ) + raise HTTPException(status_code=500, detail="Failed to populate enemy faction - check logs") + + # Return members list for frontend (already in STATE from populate_enemy) + members = [m.model_dump() for m in STATE.enemy.values()] + + await activity_logger.log_action( + username, + "Populate Enemy Success", + f"Populated {len(members)} members from faction {data.faction_id}" + ) + + return {"status": "enemy populated", "id": data.faction_id, "members": members} + + except HTTPException: + raise + except Exception as e: + error_msg = f"Error populating enemy faction {data.faction_id}: {type(e).__name__}: {str(e)}" + await activity_logger.log_action(username, "Populate Enemy Error", error_msg) + raise HTTPException(status_code=500, detail=error_msg) @router.post("/start_friendly_status") diff --git a/services/torn_api.py b/services/torn_api.py index 9b84105..79c2f9d 100644 --- a/services/torn_api.py +++ b/services/torn_api.py @@ -23,45 +23,63 @@ async def populate_faction(faction_id: int, kind: str): url = f"https://api.torn.com/v2/faction/{faction_id}?selections=members&key={TORN_API_KEY}" - async with aiohttp.ClientSession() as session: - async with session.get(url) as resp: - if resp.status != 200: - print(f"Error fetching faction {faction_id}: {resp.status}") - return False - data = await resp.json() + try: + async with aiohttp.ClientSession() as session: + async with session.get(url) as resp: + if resp.status != 200: + error_text = await resp.text() + print(f"[ERROR] Torn API returned {resp.status} for {kind} faction {faction_id}") + print(f"[ERROR] Response: {error_text[:200]}") + return False + data = await resp.json() - members_list = data.get("members", []) - if not members_list: + # Check for API error response + if "error" in data: + print(f"[ERROR] Torn API error for {kind} faction {faction_id}: {data['error']}") + return False + + members_list = data.get("members", []) + if not members_list: + print(f"[ERROR] No members found in {kind} faction {faction_id}") + return False + + member_ids = [m.get("id") for m in members_list if "id" in m] + if not member_ids: + print(f"[ERROR] No valid member IDs in {kind} faction {faction_id}") + return False + + print(f"[INFO] Fetching FFScouter data for {len(member_ids)} members from {kind} faction {faction_id}") + # Fetch FFScouter estimates + ff_data = await fetch_batch_stats(member_ids) + + received_ids = [] + async with (friendly_lock if kind == "friendly" else enemy_lock): + for m in members_list: + pid = m["id"] + est = ff_data.get(str(pid), {}).get("bs_estimate_human", "?") + status = m.get("status", {}).get("state", "Unknown") + member_data = { + "id": pid, + "name": m.get("name", "Unknown"), + "level": m.get("level", 0), + "estimate": est, + "status": status + } + await STATE.upsert_member(member_data, kind) + received_ids.append(pid) + + # Remove missing members from STATE + await STATE.remove_missing_members(received_ids, kind) + + print(f"[SUCCESS] Populated {len(received_ids)} {kind} members from faction {faction_id}") + return True + + except Exception as e: + print(f"[ERROR] Exception in populate_faction for {kind} faction {faction_id}: {type(e).__name__}: {str(e)}") + import traceback + traceback.print_exc() return False - member_ids = [m.get("id") for m in members_list if "id" in m] - if not member_ids: - return False - - # Fetch FFScouter estimates - ff_data = await fetch_batch_stats(member_ids) - - received_ids = [] - async with (friendly_lock if kind == "friendly" else enemy_lock): - for m in members_list: - pid = m["id"] - est = ff_data.get(str(pid), {}).get("bs_estimate_human", "?") - status = m.get("status", {}).get("state", "Unknown") - member_data = { - "id": pid, - "name": m.get("name", "Unknown"), - "level": m.get("level", 0), - "estimate": est, - "status": status - } - await STATE.upsert_member(member_data, kind) - received_ids.append(pid) - - # Remove missing members from STATE - await STATE.remove_missing_members(received_ids, kind) - - return True - # Status refresh loop async def refresh_status_loop(faction_id: int, kind: str, lock: asyncio.Lock, interval: int):