from dataclasses import dataclass from typing import Any, TypedDict from astrbot.api import logger from ..adapters import APIAdapterRouter from ..api_config import APIConfigError from ..fun_basic import load_template from ..request import APIClientError from ..sqlite import AsyncSQLiteDB from .cache import JSONCacheRepository DATA_PROCESSING_ERRORS = ( AttributeError, IndexError, KeyError, OSError, OverflowError, TypeError, ValueError, ) class ServiceResult(TypedDict): code: int msg: str data: Any temp: str icons: dict[str, Any] def success(data: Any, *, template: str = "") -> ServiceResult: return { "code": 200, "msg": "", "data": data, "temp": template, "icons": {}, } def failure(message: str) -> ServiceResult: return { "code": 0, "msg": message, "data": {}, "temp": "", "icons": {}, } @dataclass(frozen=True, slots=True) class ServiceContext: router: APIAdapterRouter database: AsyncSQLiteDB cache: JSONCacheRepository class BaseDomainService: """领域 Service 共享的请求、缓存和结果构建能力。""" def __init__(self, context: ServiceContext): self._router = context.router self._database = context.database self._cache = context.cache @staticmethod def new_result() -> ServiceResult: return { "code": 0, "msg": "", "data": {}, "temp": "", "icons": {}, } @staticmethod def success(data: Any, *, template: str = "") -> ServiceResult: return success(data, template=template) @staticmethod def failure(message: str) -> ServiceResult: return failure(message) async def template_result( self, template_name: str, data: Any, ) -> ServiceResult: try: template = await load_template(template_name) except FileNotFoundError: logger.exception(f"模板文件不存在: {template_name}") return failure("系统错误:模板文件不存在") return success(data, template=template) async def attach_template( self, result: ServiceResult, template_name: str, ) -> bool: try: result["temp"] = await load_template(template_name) except FileNotFoundError: logger.exception(f"模板文件不存在: {template_name}") result["msg"] = "系统错误:模板文件不存在" return False return True async def request( self, config_key: str, params: dict[str, Any] | None = None, out_key: str | None = "data", path_params: dict[str, Any] | None = None, ) -> Any | None: try: data = await self._router.request( config_key, params=params, out_key=out_key, path_params=path_params, ) if data is None: logger.warning(f"获取接口信息失败或返回空数据: {config_key}") return data except (APIConfigError, APIClientError) as exc: logger.error( f"API 请求失败: key={config_key}, " f"status={getattr(exc, 'status', None)}, " f"error={type(exc).__name__}: {exc}" ) return None