From 7eb585748da01057168cb27c08e27cb9554a56df Mon Sep 17 00:00:00 2001 From: K2Cr2O1 <2221577113@qq.com> Date: Sat, 21 Mar 2026 18:03:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor(discord-cross):=20=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E4=B8=93=E7=94=A8=E6=97=A5=E5=BF=97=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=99=A8=E6=9B=BF=E6=8D=A2=E5=85=A8=E5=B1=80=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=AE=B0=E5=BD=95=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将各模块中的全局日志记录器替换为模块专用日志记录器,以提供更清晰的日志来源标识 同时在适配器中添加会话状态检查和重连机制,提升消息发送的可靠性 --- adapters/router.py | 19 ++++---- plugins/discord-cross/config.py | 64 ++++++++++++++++++++++++++ plugins/discord-cross/handlers.py | 5 +- src/neobot/adapters/discord_adapter.py | 24 ++++++++-- 4 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 plugins/discord-cross/config.py diff --git a/adapters/router.py b/adapters/router.py index 396c005..46a5844 100644 --- a/adapters/router.py +++ b/adapters/router.py @@ -7,7 +7,7 @@ 实现原理: 1. 接收 Discord 消息 (`discord.Message`)。 -2. 将其“伪装”成 OneBot 的 `GroupMessageEvent` 或 `PrivateMessageEvent`。 +2. 将其"伪装"成 OneBot 的 `GroupMessageEvent` 或 `PrivateMessageEvent`。 3. 拦截插件调用的 `event.reply()` 方法。 4. 将插件返回的 OneBot `MessageSegment` 转换为 Discord 格式并发送。 """ @@ -227,8 +227,9 @@ class DiscordToOneBotConverter: Returns: 伪装后的 OneBot 事件对象 """ - # 在方法内部导入 logger,避免作用域问题 - from core.utils.logger import logger + # 在静态方法内部创建模块专用日志记录器 + from core.utils.logger import ModuleLogger + mod_logger = ModuleLogger("DiscordConverter") # 1. 提取基础信息 user_id = discord_message.author.id @@ -289,36 +290,36 @@ class DiscordToOneBotConverter: # 添加附件信息 if discord_message.attachments: - logger.debug(f"[DiscordToOneBotConverter] 检测到 {len(discord_message.attachments)} 个附件") + mod_logger.debug(f"[DiscordToOneBotConverter] 检测到 {len(discord_message.attachments)} 个附件") for attachment in discord_message.attachments: filename = attachment.filename.lower() - logger.debug(f"[DiscordToOneBotConverter] 处理附件: {attachment.filename}, MIME: {attachment.content_type}") + mod_logger.debug(f"[DiscordToOneBotConverter] 处理附件: {attachment.filename}, MIME: {attachment.content_type}") # 检查是否是语音文件 if filename.endswith(('.amr', '.silk', '.mp3', '.wav', '.ogg', '.m4a')): seg = OneBotMessageSegment.record(attachment.url) seg.data["filename"] = attachment.filename message_list.append(seg) raw_message += f"\n[语音: {attachment.filename}]" - logger.debug(f"[DiscordToOneBotConverter] 识别为语音文件: {attachment.filename}") + mod_logger.debug(f"[DiscordToOneBotConverter] 识别为语音文件: {attachment.filename}") elif filename.endswith(('.mp4', '.avi', '.mkv', '.mov', '.flv', '.wmv')): seg = OneBotMessageSegment.video(attachment.url) seg.data["filename"] = attachment.filename message_list.append(seg) raw_message += f"\n[视频: {attachment.filename}]" - logger.debug(f"[DiscordToOneBotConverter] 识别为视频文件: {attachment.filename}") + mod_logger.debug(f"[DiscordToOneBotConverter] 识别为视频文件: {attachment.filename}") elif filename.endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp')): image_type = "gif" if filename.endswith('.gif') else None seg = OneBotMessageSegment.image(attachment.url, image_type=image_type) seg.data["filename"] = attachment.filename message_list.append(seg) raw_message += f"\n[图片: {attachment.filename}]" - logger.debug(f"[DiscordToOneBotConverter] 识别为图片文件: {attachment.filename}") + mod_logger.debug(f"[DiscordToOneBotConverter] 识别为图片文件: {attachment.filename}") else: seg = OneBotMessageSegment.file(attachment.url) seg.data["filename"] = attachment.filename message_list.append(seg) raw_message += f"\n[文件: {attachment.filename}]" - logger.success(f"[DiscordToOneBotConverter] 识别为普通文件: {attachment.filename}") + mod_logger.success(f"[DiscordToOneBotConverter] 识别为普通文件: {attachment.filename}") # 添加贴纸 (Stickers) 信息 if hasattr(discord_message, 'stickers') and discord_message.stickers: diff --git a/plugins/discord-cross/config.py b/plugins/discord-cross/config.py new file mode 100644 index 0000000..28ab030 --- /dev/null +++ b/plugins/discord-cross/config.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +""" +跨平台消息互通插件配置模块 +""" +import os +from typing import Dict, Any +from core.utils.logger import ModuleLogger + +# 创建模块专用日志记录器 +logger = ModuleLogger("CrossPlatformConfig") + +class CrossPlatformConfig: + def __init__(self): + self.CROSS_PLATFORM_MAP: Dict[int, Dict[str, Any]] = {} + self.CROSS_PLATFORM_CHANNEL = "neobot_cross_platform" + self.ENABLE_CROSS_PLATFORM = True + + # DeepSeek API 配置 + self.DEEPSEEK_API_KEY = "sk-Cn4BeHyTHDPRKuDadLy6dUnjSSHxrz5wQa54ZFAdQovXguLD" + self.DEEPSEEK_API_URL = "https://api.gptgod.online/v1/chat/completions" + self.DEEPSEEK_MODEL = "gemini-3-flash-preview" + + # 是否启用翻译功能 + self.ENABLE_TRANSLATION = True + + async def reload(self): + """重新加载配置""" + try: + config_path = os.path.join(os.path.dirname(__file__), "..", "..", "config.toml") + + if os.path.exists(config_path): + try: + import tomllib + except ImportError: + import tomli as tomllib + + with open(config_path, "rb") as f: + config_data = tomllib.load(f) + + cross_platform_config = config_data.get("cross_platform", {}) + self.ENABLE_CROSS_PLATFORM = cross_platform_config.get("enabled", True) + + # 重新加载映射配置 + mappings = cross_platform_config.get("mappings", {}) + self.CROSS_PLATFORM_MAP.clear() + + if isinstance(mappings, dict) and mappings: + for key, value in mappings.items(): + if isinstance(value, dict) and "qq_group_id" in value: + try: + discord_id = int(key) if str(key).isdigit() else int(str(key).split('.')[-1]) + self.CROSS_PLATFORM_MAP[discord_id] = { + "qq_group_id": int(value.get("qq_group_id", 0)), + "name": value.get("name", "") + } + except (ValueError, AttributeError): + continue + + logger.success(f"[CrossPlatform] 配置已重新加载: {len(self.CROSS_PLATFORM_MAP)} 个映射") + + except Exception as e: + logger.error(f"[CrossPlatform] 重新加载配置失败: {e}") + +config = CrossPlatformConfig() diff --git a/plugins/discord-cross/handlers.py b/plugins/discord-cross/handlers.py index fb56424..fe2efff 100644 --- a/plugins/discord-cross/handlers.py +++ b/plugins/discord-cross/handlers.py @@ -9,11 +9,14 @@ from core.managers.command_manager import matcher from models.events.message import GroupMessageEvent, MessageEvent from models.message import MessageSegment from core.permission import Permission -from core.utils.logger import logger +from core.utils.logger import ModuleLogger from .config import config from .parser import parse_forward_nodes from .sender import forward_discord_to_qq, forward_qq_to_discord +# 创建模块专用日志记录器 +logger = ModuleLogger("CrossPlatform") + async def handle_discord_message( username: str, discriminator: str, diff --git a/src/neobot/adapters/discord_adapter.py b/src/neobot/adapters/discord_adapter.py index b9565e5..7ba627f 100644 --- a/src/neobot/adapters/discord_adapter.py +++ b/src/neobot/adapters/discord_adapter.py @@ -188,7 +188,12 @@ class DiscordAdapter(discord.Client if DISCORD_AVAILABLE else object): self.logger.error(f"[DiscordAdapter] 未找到频道: {channel_id}") return - self.logger.info(f"[DiscordAdapter] 正在发送消息到频道 {channel_id}") + # 检查会话状态 + if not self.is_closed(): + self.logger.info(f"[DiscordAdapter] 正在发送消息到频道 {channel_id}") + else: + self.logger.error(f"[DiscordAdapter] 会话已关闭,无法发送消息到频道 {channel_id}") + return embed = None if embed_data: @@ -271,9 +276,20 @@ class DiscordAdapter(discord.Client if DISCORD_AVAILABLE else object): self.logger.error(f"[DiscordAdapter] 下载附件失败: {attachment_url}, 错误: {e}") if content or files or embed: - await channel.send(content=content, files=files if files else None, embed=embed) - - self.logger.success(f"[DiscordAdapter] 消息已发送到频道 {channel_id}") + try: + await channel.send(content=content, files=files if files else None, embed=embed) + self.logger.success(f"[DiscordAdapter] 消息已发送到频道 {channel_id}") + except Exception as send_error: + self.logger.error(f"[DiscordAdapter] 发送消息失败 (channel.send): {send_error}") + # 如果发送失败,尝试检查会话状态 + if self.is_closed(): + self.logger.warning(f"[DiscordAdapter] 会话已关闭,将触发重连") + await self.close() + # 重新启动客户端 + asyncio.create_task(self.start_client()) + raise + else: + self.logger.debug(f"[DiscordAdapter] 没有内容需要发送到频道 {channel_id}") except Exception as e: self.logger.error(f"[DiscordAdapter] 发送消息失败: {e}")