"""Async API client used by the Discord adapter.""" import os import httpx class ApiClient: def __init__(self, discord_id, display_name): self.discord_id = str(discord_id) self.display_name = display_name self.api_url = os.getenv("API_URL", "http://127.0.0.1:5000").rstrip("/") self.service_key = os.getenv("BOT_API_KEY", "") self.token = None self.user_uuid = None self.timezone = os.getenv("DEFAULT_TIMEZONE", "UTC") self.http = httpx.AsyncClient(timeout=10.0) async def authenticate(self): headers = {"Authorization": f"Bearer {self.service_key}"} try: response = await self.http.post( f"{self.api_url}/api/auth/discord/session", headers=headers, json={ "discord_id": self.discord_id, "display_name": self.display_name, }, ) except httpx.HTTPError: return {"error": "API unavailable"}, 503 data = _response_json(response) if response.status_code == 200: self.token = data.get("token") self.user_uuid = data.get("user_uuid") self.timezone = data.get("timezone") or self.timezone return data, response.status_code async def request(self, method, endpoint, data=None, params=None): if not self.token: _, status = await self.authenticate() if status != 200: return {"error": "authentication failed"}, status try: response = await self._request( method, endpoint, self.token, data=data, params=params, ) except httpx.HTTPError: return {"error": "API unavailable"}, 503 if response.status_code == 401: authResult, status = await self.authenticate() if status != 200: return authResult, status try: response = await self._request( method, endpoint, self.token, data=data, params=params, ) except httpx.HTTPError: return {"error": "API unavailable"}, 503 return _response_json(response), response.status_code async def service_request(self, method, endpoint, data=None): try: response = await self._request( method, endpoint, self.service_key, data=data ) except httpx.HTTPError: return {"error": "API unavailable"}, 503 return _response_json(response), response.status_code async def _request(self, method, endpoint, token, data=None, params=None): requestOptions = { "headers": {"Authorization": f"Bearer {token}"}, "params": params, } if data is not None: requestOptions["json"] = data return await self.http.request( method.upper(), f"{self.api_url}{endpoint}", **requestOptions ) async def close(self): await self.http.aclose() def _response_json(response): try: return response.json() except ValueError: return {}