新增 Telegram 渠道扩展,支持在 Yuxi 平台中集成 Telegram 即时通讯渠道。 包含以下功能模块: - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - webhook: Webhook 事件处理 - polling: 长轮询模式 - outbound: 外发消息管理 - streaming: 流式消息处理 - pairing: 用户配对与绑定 - security: 安全校验 - dedupe: 消息去重 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - actions: 动作处理 - inline_keyboard: 内联键盘 - native_commands: 原生指令 - chat: 聊天管理 - delivery: 消息送达确认 - media: 媒体资源处理 - profile: 用户资料 - reactions: 表情反应 - sticker: 贴纸处理 - types: 类型定义
90 lines
3.0 KiB
Python
90 lines
3.0 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
|
|
from yuxi.channel.extensions.telegram.config import TelegramConfigAdapter
|
|
from yuxi.channel.extensions.telegram.polling import TelegramPolling
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class TelegramGateway:
|
|
|
|
def __init__(self):
|
|
self._config_adapter = TelegramConfigAdapter()
|
|
self._polling = TelegramPolling()
|
|
self._tasks: list[asyncio.Task] = []
|
|
self._running = False
|
|
self._queue: asyncio.Queue | None = None
|
|
self._abort_event: asyncio.Event | None = None
|
|
self._account: dict = {}
|
|
|
|
async def start(self, ctx) -> object:
|
|
account = await self._resolve_account(ctx)
|
|
self._account = account
|
|
if not account.get("token"):
|
|
logger.warning("telegram account %s not configured, skipping start", account.get("account_id"))
|
|
return {"running": False, "reason": "not-configured"}
|
|
|
|
self._queue = asyncio.Queue(maxsize=1000)
|
|
self._abort_event = asyncio.Event()
|
|
self._running = True
|
|
|
|
webhook_url = account.get("webhook_url", "")
|
|
if webhook_url:
|
|
task = asyncio.create_task(
|
|
self._start_webhook_mode(account, self._queue, self._abort_event)
|
|
)
|
|
else:
|
|
task = asyncio.create_task(
|
|
self._polling.start(account, self._queue, self._abort_event)
|
|
)
|
|
|
|
self._tasks.append(task)
|
|
logger.info("telegram gateway started for account %s (mode=%s)", account.get("account_id"),
|
|
"webhook" if webhook_url else "polling")
|
|
return {"running": True, "account_id": account.get("account_id"), "queue": self._queue}
|
|
|
|
async def stop(self, ctx) -> None:
|
|
self._running = False
|
|
|
|
if self._abort_event:
|
|
self._abort_event.set()
|
|
|
|
await self._polling.stop()
|
|
|
|
for task in self._tasks:
|
|
task.cancel()
|
|
self._tasks.clear()
|
|
|
|
if self._account.get("webhook_url"):
|
|
from yuxi.channel.extensions.telegram.webhook import stop_webhook
|
|
|
|
await stop_webhook(self._account)
|
|
|
|
from yuxi.channel.extensions.telegram.outbound import TelegramOutbound
|
|
|
|
await TelegramOutbound.close_client()
|
|
|
|
self._queue = None
|
|
self._abort_event = None
|
|
self._account = {}
|
|
|
|
logger.info("telegram gateway stopped")
|
|
|
|
async def _start_webhook_mode(self, account: dict, queue: asyncio.Queue, abort_event: asyncio.Event) -> None:
|
|
from yuxi.channel.extensions.telegram.webhook import start_webhook
|
|
|
|
await start_webhook(account, queue)
|
|
|
|
while not abort_event.is_set():
|
|
await asyncio.sleep(1)
|
|
|
|
async def _resolve_account(self, ctx) -> dict:
|
|
config = getattr(ctx, "config", {}) if ctx else {}
|
|
account_id = getattr(ctx, "account_id", "default")
|
|
|
|
self._config_adapter.list_account_ids(config)
|
|
return await self._config_adapter.resolve_account(account_id)
|