Skip to content

Commit 29dbd08

Browse files
authored
fix(core): 优化 File 组件处理逻辑并增强 OneBot 驱动层路径兼容性 (#5391)
* 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 系统下的文件操作鲁棒性。
1 parent 00b0118 commit 29dbd08

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

astrbot/core/message/components.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,13 +720,38 @@ async def get_file(self, allow_return_url: bool = False) -> str:
720720
if allow_return_url and self.url:
721721
return self.url
722722

723-
if self.file_ and os.path.exists(self.file_):
724-
return os.path.abspath(self.file_)
723+
if self.file_:
724+
path = self.file_
725+
if path.startswith("file://"):
726+
# 处理 file:// (2 slashes) 或 file:/// (3 slashes)
727+
# pathlib.as_uri() 通常生成 file:///
728+
path = path[7:]
729+
# 兼容 Windows: file:///C:/path -> /C:/path -> C:/path
730+
if (
731+
os.name == "nt"
732+
and len(path) > 2
733+
and path[0] == "/"
734+
and path[2] == ":"
735+
):
736+
path = path[1:]
737+
738+
if os.path.exists(path):
739+
return os.path.abspath(path)
725740

726741
if self.url:
727742
await self._download_file()
728743
if self.file_:
729-
return os.path.abspath(self.file_)
744+
path = self.file_
745+
if path.startswith("file://"):
746+
path = path[7:]
747+
if (
748+
os.name == "nt"
749+
and len(path) > 2
750+
and path[0] == "/"
751+
and path[2] == ":"
752+
):
753+
path = path[1:]
754+
return os.path.abspath(path)
730755

731756
return ""
732757

astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ async def _from_segment_to_dict(segment: BaseMessageComponent) -> dict:
4545
if isinstance(segment, File):
4646
# For File segments, we need to handle the file differently
4747
d = await segment.to_dict()
48+
file_val = d.get("data", {}).get("file", "")
49+
if file_val:
50+
import pathlib
51+
52+
try:
53+
# 使用 pathlib 处理路径,能更好地处理 Windows/Linux 差异
54+
path_obj = pathlib.Path(file_val)
55+
# 如果是绝对路径且不包含协议头 (://),则转换为标准的 file: URI
56+
if path_obj.is_absolute() and "://" not in file_val:
57+
d["data"]["file"] = path_obj.as_uri()
58+
except Exception:
59+
# 如果不是合法路径(例如已经是特定的特殊字符串),则跳过转换
60+
pass
4861
return d
4962
if isinstance(segment, Video):
5063
d = await segment.to_dict()

0 commit comments

Comments
 (0)