From 29dbd085d4870576df9e7c7ab37dade30924c0f3 Mon Sep 17 00:00:00 2001 From: Helian Nuits Date: Tue, 24 Feb 2026 21:03:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(core):=20=E4=BC=98=E5=8C=96=20File=20?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=20OneBot=20=E9=A9=B1=E5=8A=A8=E5=B1=82?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E5=85=BC=E5=AE=B9=E6=80=A7=20(#5391)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性 原因 (Necessity): 1. 内核一致性:AstrBot 内核的 Record 和 Video 组件均具备识别 `file:///` 协议头的逻辑,但 File 组件此前缺失此功能,导致行为不统一。 2. OneBot 协议合规:OneBot 11 标准要求本地文件路径必须使用 `file:///` 协议头。此前驱动层未对裸路径进行自动转换,导致发送本地文件时常触发 retcode 1200 (识别URL失败) 错误。 3. 容器环境适配:在 Docker 等路径隔离环境下,裸路径更容易因驱动或协议端的解析歧义而失效。 更改 (Changes): - [astrbot/core/message/components.py]: - 在 File.get_file() 中增加对 `file:///` 前缀的识别与剥离逻辑,使其与 Record/Video 组件行为对齐。 - [astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py]: - 在发送文件前增加自动修正逻辑:若路径为绝对路径且未包含协议头,驱动层将自动补全 `file:///` 前缀。 - 对 http、base64 及已有协议头,确保不干扰原有的正常传输逻辑。 影响 (Impact): - 以完全兼容的方式增强了文件发送的鲁棒性。 - 解决了插件在发送日志等本地生成的压缩包时,因路径格式不规范导致的发送失败问题。 * refactor(core): 根据 cr 建议,规范化文件 URI 生成与解析逻辑,优化跨平台兼容性 原因 (Necessity): 1. 修复原生路径与 URI 转换在 Windows 下的不对称问题。 2. 规范化 file: 协议头处理,确保符合 RFC 标准并能在 Linux/Windows 间稳健切换。 3. 增强协议判定准确度,防止对普通绝对路径的误处理。 更改 (Changes): - [astrbot/core/platform/sources/aiocqhttp]: - 弃用手动拼接,改用 `pathlib.Path.as_uri()` 生成标准 URI。 - 将协议检测逻辑从前缀匹配优化为包含性检测 ("://")。 - [astrbot/core/message/components]: - 重构 `File.get_file` 解析逻辑,支持对称处理 2/3 斜杠格式。 - 针对 Windows 环境增加了对 `file:///C:/` 格式的自动修正,避免 `os.path` 识别失效。 - [data/plugins/astrbot_plugin_logplus]: - 在直接 API 调用中同步应用 URI 规范化处理。 影响 (Impact): - 解决 Docker 环境中因路径不规范导致的 "识别URL失败" 报错。 - 提升了本体框架在 Windows 系统下的文件操作鲁棒性。 --- astrbot/core/message/components.py | 31 +++++++++++++++++-- .../aiocqhttp/aiocqhttp_message_event.py | 13 ++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/astrbot/core/message/components.py b/astrbot/core/message/components.py index a9bb09122..15265c38d 100644 --- a/astrbot/core/message/components.py +++ b/astrbot/core/message/components.py @@ -720,13 +720,38 @@ class File(BaseMessageComponent): if allow_return_url and self.url: return self.url - if self.file_ and os.path.exists(self.file_): - return os.path.abspath(self.file_) + if self.file_: + path = self.file_ + if path.startswith("file://"): + # 处理 file:// (2 slashes) 或 file:/// (3 slashes) + # pathlib.as_uri() 通常生成 file:/// + path = path[7:] + # 兼容 Windows: file:///C:/path -> /C:/path -> C:/path + if ( + os.name == "nt" + and len(path) > 2 + and path[0] == "/" + and path[2] == ":" + ): + path = path[1:] + + if os.path.exists(path): + return os.path.abspath(path) if self.url: await self._download_file() if self.file_: - return os.path.abspath(self.file_) + path = self.file_ + if path.startswith("file://"): + path = path[7:] + if ( + os.name == "nt" + and len(path) > 2 + and path[0] == "/" + and path[2] == ":" + ): + path = path[1:] + return os.path.abspath(path) return "" diff --git a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py index 99ea72731..7e42a0fd8 100644 --- a/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +++ b/astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py @@ -45,6 +45,19 @@ class AiocqhttpMessageEvent(AstrMessageEvent): if isinstance(segment, File): # For File segments, we need to handle the file differently d = await segment.to_dict() + file_val = d.get("data", {}).get("file", "") + if file_val: + import pathlib + + try: + # 使用 pathlib 处理路径,能更好地处理 Windows/Linux 差异 + path_obj = pathlib.Path(file_val) + # 如果是绝对路径且不包含协议头 (://),则转换为标准的 file: URI + if path_obj.is_absolute() and "://" not in file_val: + d["data"]["file"] = path_obj.as_uri() + except Exception: + # 如果不是合法路径(例如已经是特定的特殊字符串),则跳过转换 + pass return d if isinstance(segment, Video): d = await segment.to_dict()