新增大量渠道适配器相关的协议、策略、工具类与基础设施代码,包括: 1. 多协议定义:认证、消息、配置、网关等核心接口 2. 策略模块:上下文、群聊、去重、防抖等业务策略 3. 工具集:重试、去重、文本分块、消息格式化等SDK工具 4. 基础设施:外部进程管理、事件广播、熔断机制等 5. 账户与管道系统:账户管理、消息处理管道实现 6. 运行时服务:状态收集、维护任务、日志等后台服务
102 lines
3.3 KiB
Python
102 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from collections.abc import AsyncIterator, Awaitable, Callable
|
|
from typing import Any, ClassVar
|
|
|
|
from yuxi.channels.capabilities import CAPS_SIMPLE_TEXT, ChannelCapabilities
|
|
from yuxi.channels.meta import ChannelMeta
|
|
from yuxi.channels.models import (
|
|
ChannelMessage,
|
|
ChannelResponse,
|
|
ChannelType,
|
|
DeliveryResult,
|
|
HealthStatus,
|
|
)
|
|
|
|
|
|
class BaseChannelAdapter(ABC):
|
|
channel_id: ClassVar[str]
|
|
channel_type: ClassVar[ChannelType]
|
|
|
|
text_chunk_limit: ClassVar[int] = 4096
|
|
supports_markdown: ClassVar[bool] = False
|
|
supports_streaming: ClassVar[bool] = False
|
|
streaming_modes: ClassVar[list[str]] = ["off"]
|
|
max_media_size_mb: ClassVar[int] = 100
|
|
|
|
webhook_path: ClassVar[str | None] = None
|
|
|
|
capabilities: ClassVar[ChannelCapabilities] = CAPS_SIMPLE_TEXT
|
|
meta: ClassVar[ChannelMeta] = ChannelMeta(id="", label="")
|
|
|
|
def __init__(self, config: dict[str, Any] | None = None):
|
|
self.config = config or {}
|
|
self._message_handler: Callable[[ChannelMessage], Awaitable[None]] | None = None
|
|
|
|
@abstractmethod
|
|
async def connect(self) -> None: ...
|
|
|
|
@abstractmethod
|
|
async def disconnect(self) -> None: ...
|
|
|
|
@abstractmethod
|
|
async def send(self, response: ChannelResponse) -> DeliveryResult: ...
|
|
|
|
async def receive(self) -> AsyncIterator[ChannelMessage]:
|
|
return
|
|
yield # type: ignore[misc]
|
|
|
|
@abstractmethod
|
|
def normalize_inbound(self, raw: Any) -> ChannelMessage: ...
|
|
|
|
@abstractmethod
|
|
def format_outbound(self, response: ChannelResponse) -> Any: ...
|
|
|
|
@abstractmethod
|
|
async def health_check(self) -> HealthStatus: ...
|
|
|
|
def on_message(self, handler: Callable[[ChannelMessage], Awaitable[None]]) -> None:
|
|
self._message_handler = handler
|
|
|
|
async def _handle_message(self, message: ChannelMessage) -> None:
|
|
if self._message_handler:
|
|
await self._message_handler(message)
|
|
|
|
async def send_media(self, chat_id: str, media_type: str, data: Any) -> DeliveryResult:
|
|
raise NotImplementedError
|
|
|
|
async def edit_message(self, chat_id: str, msg_id: str, content: str) -> DeliveryResult:
|
|
raise NotImplementedError
|
|
|
|
async def delete_message(self, chat_id: str, msg_id: str) -> DeliveryResult:
|
|
raise NotImplementedError
|
|
|
|
async def send_reaction(self, chat_id: str, msg_id: str, emoji: str) -> DeliveryResult:
|
|
raise NotImplementedError
|
|
|
|
async def send_stream_chunk(self, chat_id: str, msg_id: str, chunk: str, finished: bool) -> DeliveryResult:
|
|
identity = self._build_stream_identity(chat_id, msg_id)
|
|
response = ChannelResponse(identity=identity, content=chunk)
|
|
return await self.send(response)
|
|
|
|
def _build_stream_identity(self, chat_id: str, msg_id: str) -> Any:
|
|
from yuxi.channels.models import ChannelIdentity
|
|
|
|
return ChannelIdentity(
|
|
channel_id=self.channel_id,
|
|
channel_type=self.channel_type,
|
|
channel_user_id="",
|
|
channel_chat_id=chat_id,
|
|
channel_message_id=msg_id,
|
|
)
|
|
|
|
async def verify_webhook_signature(self, headers: dict, body: bytes) -> bool:
|
|
return True
|
|
|
|
async def _refresh_token_if_needed(self) -> bool:
|
|
return True
|
|
|
|
async def pre_connect(self) -> dict:
|
|
return {}
|