81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
import asyncio
|
|
import logging
|
|
from typing import Any, Optional
|
|
|
|
import httpx
|
|
|
|
from core.config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class WorkspaceProfileClient:
|
|
"""Cliente para consultar perfil del usuario en Workspace Hub (/v1/auth/me)."""
|
|
|
|
def __init__(
|
|
self,
|
|
base_url: Optional[str] = None,
|
|
timeout_ms: Optional[int] = None,
|
|
retries: int = 2,
|
|
transport: Optional[httpx.BaseTransport] = None,
|
|
):
|
|
self.base_url = (base_url or settings.hub_api_base_url).rstrip("/")
|
|
self.timeout_s = max(0.1, float(timeout_ms or settings.HUB_PROFILE_SYNC_TIMEOUT_MS) / 1000.0)
|
|
self.retries = max(0, int(retries))
|
|
self.transport = transport
|
|
|
|
async def get_me(self, access_token: str) -> dict[str, Any]:
|
|
if not access_token:
|
|
raise ValueError("access_token is required")
|
|
|
|
headers = {"Authorization": f"Bearer {access_token}"}
|
|
url = f"{self.base_url}/v1/auth/me"
|
|
|
|
last_error: Optional[Exception] = None
|
|
for attempt in range(self.retries + 1):
|
|
try:
|
|
async with httpx.AsyncClient(
|
|
timeout=self.timeout_s,
|
|
transport=self.transport,
|
|
) as client:
|
|
response = await client.get(url, headers=headers)
|
|
|
|
if response.status_code == 200:
|
|
payload = response.json()
|
|
if not isinstance(payload, dict):
|
|
raise ValueError("Invalid workspace profile payload")
|
|
return payload
|
|
|
|
if response.status_code in (401, 403, 404):
|
|
# Errores de autenticación/autorización o endpoint no disponible:
|
|
# no vale la pena reintentar.
|
|
raise httpx.HTTPStatusError(
|
|
f"Workspace profile request failed with status {response.status_code}",
|
|
request=response.request,
|
|
response=response,
|
|
)
|
|
|
|
# Reintentar solo para errores transitorios 5xx.
|
|
if response.status_code >= 500 and attempt < self.retries:
|
|
await asyncio.sleep(0.15 * (attempt + 1))
|
|
continue
|
|
|
|
raise httpx.HTTPStatusError(
|
|
f"Workspace profile request failed with status {response.status_code}",
|
|
request=response.request,
|
|
response=response,
|
|
)
|
|
|
|
except (httpx.TimeoutException, httpx.NetworkError) as exc:
|
|
last_error = exc
|
|
if attempt >= self.retries:
|
|
break
|
|
await asyncio.sleep(0.15 * (attempt + 1))
|
|
except Exception as exc:
|
|
last_error = exc
|
|
break
|
|
|
|
if last_error:
|
|
raise last_error
|
|
raise RuntimeError("Workspace profile request failed")
|