From b0337fb70aaf04c2b10413288454703103749f0b Mon Sep 17 00:00:00 2001 From: sunlei Date: Sat, 6 Jun 2026 22:02:39 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=85=BC=E5=AE=B9=20BangDream=20?= =?UTF-8?q?=E7=9B=B8=E5=AF=B9=E7=BC=93=E5=AD=98=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ot-bangdream-tsugu-global-refactor-plan.md | 1 + .../tsugu/data-clients/cache-path.ts | 18 +++++++++-- .../bangDream/tsugu/cache-path.spec.ts | 31 +++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 test/qqbot/plugins/bangDream/tsugu/cache-path.spec.ts diff --git a/docs/qqbot-bangdream-tsugu-global-refactor-plan.md b/docs/qqbot-bangdream-tsugu-global-refactor-plan.md index 5188cba..e1c63c6 100644 --- a/docs/qqbot-bangdream-tsugu-global-refactor-plan.md +++ b/docs/qqbot-bangdream-tsugu-global-refactor-plan.md @@ -397,6 +397,7 @@ export interface TsuguHook { - 已新增 `tsugu/runtime/operation-pipeline.ts`,把主数据 ready、operation resolve、handler render、output hook 和 error hook 固定为 `TsuguOperationPipeline.run`,`TsuguApplicationService.execute` 只负责调用 pipeline。 - `scripts/bangdream-render-smoke.ps1` 已切到 `TsuguApplicationService`,本地 smoke 继续走真实应用入口,避免 facade 改造后验证脚本回退到旧链路。 - 已新增 `hook-registry.spec.ts`、`operation-pipeline.spec.ts` 和 `tsugu-application.service.spec.ts`,覆盖 hook 顺序、错误 hook、pipeline 成功/未知 operation/handler 错误、应用入口执行、字典刷新和错误字符串化;本地 Phase 7 smoke 已生成 `phase7-hook-event-50.jpg`、`phase7-hook-cutoff-detail-100-50-cn.jpg`、`phase7-hook-cutoff-recent-100-50-cn.jpg`、`phase7-pipeline-event-50.jpg`、`phase7-pipeline-cutoff-detail-100-50-cn.jpg`、`phase7-pipeline-cutoff-recent-100-50-cn.jpg`。 +- 线上 `qqbot/command/test` 复测时曾出现 `bangdream.event.search` 的 `Invalid URL`,根因按风险点固化为:缓存层不能假设所有调用方都已把 `/api`、`/assets` 相对路径解析成完整 Bestdori URL;已在 `data-clients/cache-path.ts` 增加 `resolveCacheUrl` 兜底,并新增 `cache-path.spec.ts` 覆盖相对资产路径、相对 API 路径和完整 URL。线上/远程临时 Node 调试脚本必须同时设置外层 `timeout`,并在成功和失败分支显式 `process.exit(...)`,避免 SSH 会话被后台 timer 卡住。 ## 文件迁移优先级 diff --git a/src/qqbot/plugins/bangDream/tsugu/data-clients/cache-path.ts b/src/qqbot/plugins/bangDream/tsugu/data-clients/cache-path.ts index 68399d8..40068c3 100644 --- a/src/qqbot/plugins/bangDream/tsugu/data-clients/cache-path.ts +++ b/src/qqbot/plugins/bangDream/tsugu/data-clients/cache-path.ts @@ -1,4 +1,8 @@ -import { cacheRootPath } from '@/qqbot/plugins/bangDream/tsugu/runtime/config'; +import { + bestdoriUrl, + cacheRootPath, +} from '@/qqbot/plugins/bangDream/tsugu/runtime/config'; +import { resolveBangDreamProviderUrl } from './data-provider'; import * as path from 'path'; /** @@ -8,7 +12,7 @@ import * as path from 'path'; * @returns 格式化后的文本。 */ export function getCacheDirectory(url: string): string { - const urlObj = new URL(url); + const urlObj = new URL(resolveCacheUrl(url)); let pathname = urlObj.pathname; // 如果结尾是文件名,去掉文件名 if (path.basename(pathname).indexOf('.') != -1) { @@ -28,7 +32,7 @@ export function getCacheDirectory(url: string): string { * @returns 格式化后的文本。 */ export function getFileNameFromUrl(url: string): string { - const urlObj = new URL(url); + const urlObj = new URL(resolveCacheUrl(url)); let fileName = path.basename(urlObj.pathname); // Remove query string if present @@ -58,3 +62,11 @@ function sanitizeDirectoryName(dirName: string): string { return dirName.replace(illegalChars, replacementChar); } + +function resolveCacheUrl(url: string): string { + const source = `${url || ''}`.trim(); + if (!source) { + throw new Error('cache url is empty'); + } + return resolveBangDreamProviderUrl(bestdoriUrl, source); +} diff --git a/test/qqbot/plugins/bangDream/tsugu/cache-path.spec.ts b/test/qqbot/plugins/bangDream/tsugu/cache-path.spec.ts new file mode 100644 index 0000000..fac3ce6 --- /dev/null +++ b/test/qqbot/plugins/bangDream/tsugu/cache-path.spec.ts @@ -0,0 +1,31 @@ +import * as path from 'path'; +import { + getCacheDirectory, + getFileNameFromUrl, +} from '@/qqbot/plugins/bangDream/tsugu/data-clients/cache-path'; + +describe('BangDream cache path', () => { + it('resolves relative asset paths before creating cache directories', () => { + const directory = getCacheDirectory( + '/assets/cn/event/foo/topscreen_rip/bg_eventtop.png', + ); + + expect(directory).toContain( + path.join('.kt-workspace', 'cache', 'bangdream'), + ); + expect(directory).toContain('bestdori.com'); + expect(directory).toContain( + path.join('assets', 'cn', 'event', 'foo', 'topscreen_rip'), + ); + }); + + it('resolves relative api paths before creating cache file names', () => { + expect(getFileNameFromUrl('/api/events/50.json')).toBe('50.json'); + }); + + it('keeps absolute urls unchanged for cache file names', () => { + expect(getFileNameFromUrl('https://example.com/api/events/50')).toBe( + '50.json', + ); + }); +});