* fix(discord): 修复 WebSocket 连接检测并增强跨平台文件处理

修复 Discord WebSocket 连接检测逻辑,使用正确的属性检查连接状态
为跨平台消息处理添加文件类型支持,并增加详细的调试日志
优化附件处理逻辑,确保所有文件类型都能正确识别和转发

* feat(跨平台): 优化消息处理并添加纯文本提取功能

添加 extract_text_only 函数过滤非文本标记
修改翻译逻辑仅处理纯文本内容
完善附件处理和消息内容拼接
修复仅包含表情时的消息处理问题

* refactor(discord-cross): 使用模块专用日志记录器替换全局日志记录器

将各模块中的全局日志记录器替换为模块专用日志记录器,以提供更清晰的日志来源标识
同时在适配器中添加会话状态检查和重连机制,提升消息发送的可靠性
This commit is contained in:
镀铬酸钾
2026-03-21 18:04:35 +08:00
committed by GitHub
parent 207d2d191f
commit be552a90ea
9 changed files with 58 additions and 20 deletions

View File

@@ -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}")

View File

@@ -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:

View File

@@ -3,11 +3,14 @@
跨平台消息互通插件入口
"""
import asyncio
from core.utils.logger import logger
from core.utils.logger import ModuleLogger
from .config import config
from .subscription import start_cross_platform_subscription, stop_cross_platform_subscription
from .handlers import *
# 创建模块专用日志记录器
logger = ModuleLogger("CrossPlatform")
# 插件加载时自动启动和加载配置
try:
asyncio.create_task(config.reload())

View File

@@ -4,7 +4,10 @@
"""
import os
from typing import Dict, Any
from core.utils.logger import logger
from core.utils.logger import ModuleLogger
# 创建模块专用日志记录器
logger = ModuleLogger("CrossPlatformConfig")
class CrossPlatformConfig:
def __init__(self):

View File

@@ -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,

View File

@@ -7,9 +7,12 @@ import json
import re
from typing import Dict, List, Any
from models.message import MessageSegment
from core.utils.logger import logger
from core.utils.logger import ModuleLogger
from .config import config
# 创建模块专用日志记录器
logger = ModuleLogger("CrossPlatformParser")
def extract_text_only(content: str) -> str:
"""从消息内容中提取纯文本,过滤掉非文本标记"""

View File

@@ -4,12 +4,15 @@
"""
import json
from typing import List
from core.utils.logger import logger
from core.utils.logger import ModuleLogger
from core.managers.redis_manager import redis_manager
from .config import config
from .translator import translate_with_deepseek
from .parser import format_discord_to_qq_content, format_qq_to_discord_content, extract_text_only
# 创建模块专用日志记录器
logger = ModuleLogger("CrossPlatformSender")
async def send_to_discord(channel_id: int, content: str, attachments: List[dict] = None, embed: dict = None):
"""发送消息到 Discord 频道"""
try:

View File

@@ -4,11 +4,14 @@
"""
import json
import asyncio
from core.utils.logger import logger
from core.utils.logger import ModuleLogger
from core.managers.redis_manager import redis_manager
from .config import config
from .sender import forward_discord_to_qq, forward_qq_to_discord
# 创建模块专用日志记录器
logger = ModuleLogger("CrossPlatformSubscription")
async def cross_platform_subscription_loop():
"""Redis 跨平台消息订阅循环"""
if redis_manager.redis is None:

View File

@@ -3,9 +3,12 @@
跨平台消息互通插件翻译模块
"""
from typing import Dict, List
from core.utils.logger import logger
from core.utils.logger import ModuleLogger
from .config import config
# 创建模块专用日志记录器
logger = ModuleLogger("CrossPlatformTranslator")
# 翻译上下文缓存每个通道15条消息
TRANSLATION_CONTEXT_CACHE: Dict[str, List[Dict[str, str]]] = {}
MAX_CONTEXT_MESSAGES = 15