Files

120 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""NapCat 底层动作调用服务。"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Dict, Mapping, Optional
import asyncio
try:
from aiohttp import ClientSession, ClientTimeout
AIOHTTP_AVAILABLE = True
except ImportError:
ClientSession = None # type: ignore[assignment]
ClientTimeout = None # type: ignore[assignment]
AIOHTTP_AVAILABLE = False
if TYPE_CHECKING:
from ..transport import NapCatTransportClient
class NapCatActionService:
"""NapCat 底层动作与资源访问服务。"""
def __init__(self, logger: Any, transport: "NapCatTransportClient") -> None:
"""初始化底层动作服务。
Args:
logger: 插件日志对象。
transport: NapCat 传输层客户端。
"""
self._logger = logger
self._transport = transport
async def call_action(self, action_name: str, params: Mapping[str, Any]) -> Dict[str, Any]:
"""调用 OneBot 动作并要求返回成功结果。
Args:
action_name: OneBot 动作名称。
params: 动作参数。
Returns:
Dict[str, Any]: NapCat 返回的原始响应字典。
Raises:
RuntimeError: 当动作执行失败或平台返回非成功状态时抛出。
"""
normalized_params = {str(key): value for key, value in params.items()}
try:
response = await self._transport.call_action(action_name, normalized_params)
except asyncio.CancelledError:
raise
except Exception as exc:
raise RuntimeError(f"NapCat 动作执行失败: action={action_name} error={exc}") from exc
if str(response.get("status") or "").lower() != "ok":
error_message = str(response.get("wording") or response.get("message") or "unknown")
raise RuntimeError(f"NapCat 动作返回失败: action={action_name} message={error_message}")
return response
async def call_action_data(self, action_name: str, params: Mapping[str, Any]) -> Any:
"""调用 OneBot 动作并返回 ``data`` 字段。
Args:
action_name: OneBot 动作名称。
params: 动作参数。
Returns:
Any: NapCat 响应中的 ``data`` 字段。
"""
response = await self.call_action(action_name, params)
return response.get("data")
async def safe_call_action_data(self, action_name: str, params: Mapping[str, Any]) -> Any:
"""安全调用 OneBot 动作并返回 ``data`` 字段。
Args:
action_name: OneBot 动作名称。
params: 动作参数。
Returns:
Any: 响应中的 ``data`` 字段;失败时返回 ``None``。
"""
try:
return await self.call_action_data(action_name, params)
except asyncio.CancelledError:
raise
except Exception as exc:
self._logger.warning(f"NapCat 查询动作执行失败: action={action_name} error={exc}")
return None
async def download_binary(self, url: str) -> Optional[bytes]:
"""下载远程二进制资源。
Args:
url: 资源 URL。
Returns:
Optional[bytes]: 下载到的二进制内容;失败时返回 ``None``。
"""
if not url:
return None
if not AIOHTTP_AVAILABLE or ClientSession is None or ClientTimeout is None:
self._logger.warning("NapCat 查询层缺少 aiohttp无法下载远程资源")
return None
try:
timeout = ClientTimeout(total=15)
async with ClientSession(timeout=timeout) as session:
async with session.get(url) as response:
if response.status != 200:
self._logger.warning(f"NapCat 远程资源下载失败: status={response.status} url={url}")
return None
return await response.read()
except asyncio.CancelledError:
raise
except Exception as exc:
self._logger.warning(f"NapCat 远程资源下载失败: {exc}")
return None