""" API Client for Telegram Bot Connects bot to FastAPI game server instead of using direct database access """ import os import httpx from typing import Optional, Dict, Any API_BASE_URL = os.getenv("API_BASE_URL", "http://echoes_of_the_ashes_api:8000") API_INTERNAL_KEY = os.getenv("API_INTERNAL_KEY", "internal-bot-access-key-change-me") class GameAPIClient: """Client for interacting with the FastAPI game server""" def __init__(self): self.base_url = API_BASE_URL self.headers = { "X-Internal-Key": API_INTERNAL_KEY, "Content-Type": "application/json" } self.client = httpx.AsyncClient(timeout=30.0) async def close(self): """Close the HTTP client""" await self.client.aclose() # ==================== Player Management ==================== async def get_player(self, telegram_id: int) -> Optional[Dict[str, Any]]: """Get player by telegram ID""" try: response = await self.client.get( f"{self.base_url}/api/internal/player/telegram/{telegram_id}", headers=self.headers ) if response.status_code == 404: return None response.raise_for_status() return response.json() except Exception as e: print(f"Error getting player: {e}") return None async def create_player(self, telegram_id: int, name: str) -> Optional[Dict[str, Any]]: """Create a new player""" try: response = await self.client.post( f"{self.base_url}/api/internal/player", headers=self.headers, json={"telegram_id": telegram_id, "name": name} ) response.raise_for_status() return response.json() except Exception as e: print(f"Error creating player: {e}") return None async def update_player(self, telegram_id: int, updates: Dict[str, Any]) -> bool: """Update player data""" try: response = await self.client.patch( f"{self.base_url}/api/internal/player/telegram/{telegram_id}", headers=self.headers, json=updates ) response.raise_for_status() return True except Exception as e: print(f"Error updating player: {e}") return False # ==================== Location & Movement ==================== async def get_location(self, location_id: str) -> Optional[Dict[str, Any]]: """Get location details""" try: response = await self.client.get( f"{self.base_url}/api/internal/location/{location_id}", headers=self.headers ) if response.status_code == 404: return None response.raise_for_status() return response.json() except Exception as e: print(f"Error getting location: {e}") return None async def move_player(self, telegram_id: int, direction: str) -> Optional[Dict[str, Any]]: """Move player in a direction""" try: response = await self.client.post( f"{self.base_url}/api/internal/player/telegram/{telegram_id}/move", headers=self.headers, json={"direction": direction} ) response.raise_for_status() return response.json() except httpx.HTTPStatusError as e: # Return error details return {"success": False, "error": e.response.json().get("detail", str(e))} except Exception as e: print(f"Error moving player: {e}") return {"success": False, "error": str(e)} # ==================== Combat ==================== async def start_combat(self, telegram_id: int, npc_id: str) -> Optional[Dict[str, Any]]: """Start combat with an NPC""" try: response = await self.client.post( f"{self.base_url}/api/internal/combat/start", headers=self.headers, json={"telegram_id": telegram_id, "npc_id": npc_id} ) response.raise_for_status() return response.json() except Exception as e: print(f"Error starting combat: {e}") return None async def get_combat(self, telegram_id: int) -> Optional[Dict[str, Any]]: """Get active combat state""" try: response = await self.client.get( f"{self.base_url}/api/internal/combat/telegram/{telegram_id}", headers=self.headers ) if response.status_code == 404: return None response.raise_for_status() return response.json() except Exception as e: print(f"Error getting combat: {e}") return None async def combat_action(self, telegram_id: int, action: str) -> Optional[Dict[str, Any]]: """Perform a combat action (attack, defend, flee)""" try: response = await self.client.post( f"{self.base_url}/api/internal/combat/telegram/{telegram_id}/action", headers=self.headers, json={"action": action} ) response.raise_for_status() return response.json() except Exception as e: print(f"Error performing combat action: {e}") return None # ==================== Inventory ==================== async def get_inventory(self, telegram_id: int) -> Optional[Dict[str, Any]]: """Get player's inventory""" try: response = await self.client.get( f"{self.base_url}/api/internal/player/telegram/{telegram_id}/inventory", headers=self.headers ) response.raise_for_status() return response.json() except Exception as e: print(f"Error getting inventory: {e}") return None async def use_item(self, telegram_id: int, item_db_id: int) -> Optional[Dict[str, Any]]: """Use an item from inventory""" try: response = await self.client.post( f"{self.base_url}/api/internal/player/telegram/{telegram_id}/use_item", headers=self.headers, json={"item_db_id": item_db_id} ) response.raise_for_status() return response.json() except Exception as e: print(f"Error using item: {e}") return None async def equip_item(self, telegram_id: int, item_db_id: int) -> Optional[Dict[str, Any]]: """Equip/unequip an item""" try: response = await self.client.post( f"{self.base_url}/api/internal/player/telegram/{telegram_id}/equip", headers=self.headers, json={"item_db_id": item_db_id} ) response.raise_for_status() return response.json() except Exception as e: print(f"Error equipping item: {e}") return None # Global API client instance api_client = GameAPIClient()