"""Usage service: fully proxied to sub2api (user JWT for user-scoped endpoints).""" from __future__ import annotations from typing import Any from fastapi import HTTPException from sqlalchemy.ext.asyncio import AsyncSession from app.core.exceptions import BadRequestError from app.integrations.sub2api import user as sub2api_user from app.integrations.sub2api.client import ( Sub2APIError, Sub2APIReauthRequired, Sub2APITransportError, ) from app.models import User from app.services.sub2api_session import ensure_access_token def _require_binding(user: User) -> int: if not user.sub2api_user_id: raise BadRequestError("账号未完成 sub2api 绑定,请重新登录") return user.sub2api_user_id def _translate(exc: Exception) -> HTTPException: if isinstance(exc, Sub2APIReauthRequired): return HTTPException(status_code=401, detail="sub2api_reauth_required") if isinstance(exc, Sub2APIError): status = exc.http_status or 502 if status < 400 or status >= 600: status = 502 return HTTPException(status_code=status, detail=exc.message or exc.reason or "upstream_error") return HTTPException(status_code=504, detail="upstream_timeout") class UsageService: @staticmethod async def list_logs(db: AsyncSession, user: User, **params: Any) -> dict[str, Any]: _require_binding(user) try: token = await ensure_access_token(db, user) return await sub2api_user.list_usage(token, **params) except (Sub2APIError, Sub2APITransportError) as exc: raise _translate(exc) from exc @staticmethod async def stats(db: AsyncSession, user: User, **params: Any) -> dict[str, Any]: _require_binding(user) try: token = await ensure_access_token(db, user) return await sub2api_user.usage_stats(token, **params) except (Sub2APIError, Sub2APITransportError) as exc: raise _translate(exc) from exc @staticmethod async def dashboard_stats(db: AsyncSession, user: User) -> dict[str, Any]: _require_binding(user) try: token = await ensure_access_token(db, user) return await sub2api_user.dashboard_stats(token) except (Sub2APIError, Sub2APITransportError) as exc: raise _translate(exc) from exc @staticmethod async def dashboard_trend(db: AsyncSession, user: User, **params: Any) -> dict[str, Any]: _require_binding(user) try: token = await ensure_access_token(db, user) return await sub2api_user.dashboard_trend(token, **params) except (Sub2APIError, Sub2APITransportError) as exc: raise _translate(exc) from exc @staticmethod async def dashboard_models(db: AsyncSession, user: User, **params: Any) -> dict[str, Any]: _require_binding(user) try: token = await ensure_access_token(db, user) return await sub2api_user.dashboard_models(token, **params) except (Sub2APIError, Sub2APITransportError) as exc: raise _translate(exc) from exc @staticmethod async def dashboard_api_keys_usage( db: AsyncSession, user: User, api_key_ids: list[int] ) -> dict[str, Any]: _require_binding(user) try: token = await ensure_access_token(db, user) return await sub2api_user.dashboard_api_keys_usage(token, api_key_ids) except (Sub2APIError, Sub2APITransportError) as exc: raise _translate(exc) from exc