新增 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: 类型定义
183 lines
6.9 KiB
Python
183 lines
6.9 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class TelegramChat:
|
|
|
|
def __init__(self, outbound):
|
|
self._outbound = outbound
|
|
|
|
async def _call(self, token: str, method: str, payload: dict) -> dict | list | int | None:
|
|
return await self._outbound._api_call(token, method, payload)
|
|
|
|
async def get_chat(self, account_id: str, chat_id: str) -> dict | None:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return None
|
|
result = await self._call(token, "getChat", {"chat_id": chat_id})
|
|
return result if isinstance(result, dict) else None
|
|
|
|
async def get_chat_member(
|
|
self, account_id: str, chat_id: str, user_id: int,
|
|
) -> dict | None:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return None
|
|
result = await self._call(
|
|
token, "getChatMember", {"chat_id": chat_id, "user_id": user_id},
|
|
)
|
|
return result if isinstance(result, dict) else None
|
|
|
|
async def get_chat_member_count(self, account_id: str, chat_id: str) -> int | None:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return None
|
|
result = await self._call(token, "getChatMemberCount", {"chat_id": chat_id})
|
|
return result if isinstance(result, int) else None
|
|
|
|
async def get_chat_administrators(self, account_id: str, chat_id: str) -> list[dict] | None:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return None
|
|
result = await self._call(token, "getChatAdministrators", {"chat_id": chat_id})
|
|
return result if isinstance(result, list) else None
|
|
|
|
async def get_user_profile_photos(
|
|
self, account_id: str, user_id: int, *, limit: int = 100,
|
|
) -> dict | None:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return None
|
|
result = await self._call(
|
|
token, "getUserProfilePhotos",
|
|
{"user_id": user_id, "limit": limit},
|
|
)
|
|
return result if isinstance(result, dict) else None
|
|
|
|
async def pin_message(
|
|
self, account_id: str, chat_id: str, message_id: int, *,
|
|
disable_notification: bool = False,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
result = await self._call(
|
|
token, "pinChatMessage",
|
|
{"chat_id": chat_id, "message_id": message_id, "disable_notification": disable_notification},
|
|
)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def unpin_message(
|
|
self, account_id: str, chat_id: str, message_id: int | None = None,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
payload: dict[str, Any] = {"chat_id": chat_id}
|
|
if message_id:
|
|
payload["message_id"] = message_id
|
|
result = await self._call(token, "unpinChatMessage", payload)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def create_forum_topic(
|
|
self, account_id: str, chat_id: str, name: str, *,
|
|
icon_color: int | None = None, icon_custom_emoji_id: str | None = None,
|
|
) -> dict | None:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return None
|
|
payload: dict[str, Any] = {"chat_id": chat_id, "name": name}
|
|
if icon_color is not None:
|
|
payload["icon_color"] = icon_color
|
|
if icon_custom_emoji_id:
|
|
payload["icon_custom_emoji_id"] = icon_custom_emoji_id
|
|
result = await self._call(token, "createForumTopic", payload)
|
|
return result if isinstance(result, dict) else None
|
|
|
|
async def close_forum_topic(
|
|
self, account_id: str, chat_id: str, message_thread_id: int,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
result = await self._call(
|
|
token, "closeForumTopic",
|
|
{"chat_id": chat_id, "message_thread_id": message_thread_id},
|
|
)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def reopen_forum_topic(
|
|
self, account_id: str, chat_id: str, message_thread_id: int,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
result = await self._call(
|
|
token, "reopenForumTopic",
|
|
{"chat_id": chat_id, "message_thread_id": message_thread_id},
|
|
)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def delete_forum_topic(
|
|
self, account_id: str, chat_id: str, message_thread_id: int,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
result = await self._call(
|
|
token, "deleteForumTopic",
|
|
{"chat_id": chat_id, "message_thread_id": message_thread_id},
|
|
)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def edit_forum_topic(
|
|
self, account_id: str, chat_id: str, message_thread_id: int, *,
|
|
name: str | None = None, icon_custom_emoji_id: str | None = None,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
payload: dict[str, Any] = {"chat_id": chat_id, "message_thread_id": message_thread_id}
|
|
if name:
|
|
payload["name"] = name
|
|
if icon_custom_emoji_id:
|
|
payload["icon_custom_emoji_id"] = icon_custom_emoji_id
|
|
result = await self._call(token, "editForumTopic", payload)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def edit_general_forum_topic(
|
|
self, account_id: str, chat_id: str, name: str,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
result = await self._call(
|
|
token, "editGeneralForumTopic",
|
|
{"chat_id": chat_id, "name": name},
|
|
)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def set_chat_member_tag(
|
|
self, account_id: str, chat_id: str, user_id: int, tag: str,
|
|
) -> bool:
|
|
token = await self._resolve_token(account_id)
|
|
if not token:
|
|
return False
|
|
result = await self._call(
|
|
token, "setChatMemberTag",
|
|
{"chat_id": chat_id, "user_id": user_id, "tag": tag},
|
|
)
|
|
return result is not None and not isinstance(result, dict)
|
|
|
|
async def _resolve_token(self, account_id: str | None) -> str:
|
|
from yuxi.channel.extensions.telegram.config import TelegramConfigAdapter
|
|
|
|
adapter = TelegramConfigAdapter()
|
|
aid = account_id or "default"
|
|
account = await adapter.resolve_account(aid)
|
|
return account.get("token", "")
|