-
released this
2026-09-17 03:39:36 +08:00 | 7 commits to main since this releaseOpenDance Studio -- Web 管理服务端 v0.7.3
两个真实缺陷修复(均在生产部署上复现并定位)。
契约无变更(仍为
rest-api 0.5.0/websocket-keypoints 0.2.0/data-models 0.7.0/
skeleton-topology 0.2.0/model-formats 0.5.0/database 0.4.0)。一、场景根本传不上来:diskStorage 却按内存存储判断
现象:
POST /api/scenes一律 400「上传场景必须带 file 字段(.glb 为主…)」,
而同一份 multipart 请求打/api/models返回 201(已用 curl 对照验证)。根因:上传中间件在
storage.module.ts里用的是 multer 的diskStorage
(先落${STORAGE_DIR}/tmp,避免 512 MiB 级 VRM 打爆进程内存),落盘后的文件对象
只有path、没有buffer;而ScenesService.create()当初按内存存储写:if (!file || !file.buffer || file.buffer.length === 0) { /* 400 */ }file.buffer恒为undefined→ 任何场景都传不上来。修复:与 models / motions 统一到同一套上传处理:
requireUploadedFile(file)—— 校验确实落盘,并修正 busboy 按 latin1 解出的中文/日文文件名;- 直接导入(
.glb/.gltf)→storage.persistTempFile(AssetKind.Scene, upload.path, …)
—— 归档并顺带清理临时文件; - 需转换(
.zip/.pmx/.fbx)→readFile(upload.path)取 buffer 后转换 →persistBuffer,
并在finally中unlink(upload.path); - 体积上限用
upload.size判断(UPLOAD_MAX_BYTES),超限 400 且不落盘。
全局排查过同类写法:除注释外,代码里已无按
file.buffer处理上传的地方。二、场景表不可用会拖垮整站
现象(生产):数据库缺
scenes表,于是请求 结果 /api/songs、/api/motions、/api/models200 /api/scenes、/api/scenes/:id500 /api/catalog/export、/api/catalog/version500 ← 客户端拉不到任何目录 /api/reviews?status=pending500 ← 管理端待审列表打不开 而
/health显示database.connected true、migrationsPending 0—— 因为
DataSource.showMigrations()只比较代码里加载到的迁移;部署的dist/migrations/
若缺AddScenes.js,它根本不在比较集合里,于是"没有待执行迁移"但表并不存在。契约与文档都写明场景是可选资源(没有可用场景时客户端回退内置空场景),
因此改为降级而不是 500:ScenesService.queryScenes():数据库层面失败 → 返回空结果、只记一次日志、
原因写入diagnostics();下一次查询成功即自动复位;ReviewsService.listByStatus():场景查询单独catch,待审列表照常返回其它资源;/health新增scenes: { available, error }—— 降级但绝不静默。
三、新增诊断脚本
web-server/scripts/diagnose-scenes.mjs(默认只读)打印运行期真实连的库、表清单、
typeorm_migrations记录、代码实际加载的迁移、
scenes实际列 vs 实体期望列的逐列 diff;--fix仅在缺表时用迁移里同一份 DDL
幂等补表。cd <APP_DIR>/web-server set -a; . ../deploy/.env; set +a node scripts/diagnose-scenes.mjs # 只读诊断 node scripts/diagnose-scenes.mjs --fix # 仅在缺表时补表(幂等)四、顺带修正
models.controller.ts的误导性注释:模型上传不接受isPrimary/status
(契约:上传一律pending,默认模型由审核通过时带setPrimary=true或
POST /api/models/{id}/primary设定);test/smoke.mjs此前按错误预期断言「isPrimary 已置位」,已改为契约流程
(上传断言pending+isPrimary=false→ 审核带setPrimary=true→ 断言isPrimary=true);
另给目录导出/指纹等检查补上失败细节(HTTP 状态 + 响应体),并把待审列表查询的
pageSize放大到 200(避免库里待审项多时新条目被挤出第一页);deploy/proxy/README.md第九节更正一次误判:Gitea 附件接口本身是好的 ——
它的 multipart 字段名是attachment,用file=会得到
HTTP 500 {"message":"","url":"…/api/swagger"}(空消息,极易误判成"服务器磁盘写满")。
本节同时记录了两种正确的上传写法与复验命令。
⚠️ 仍然存在、需要运维处理的唯一上传限制:IIS 的
maxAllowedContentLength
还是默认的 30,000,000 字节,37 MB 的 Windows 整包上传仍返回 HTTP 413。
请按deploy/proxy/README.md9.2 放开到 256 MB。校验
npm run verify通过:contracts:check(六项一致 + 35 条路由一致 + 版本一致)、
tsc --noEmit、22 文件 / 281 项测试、nest build、启动冒烟;- 新增
test/scene-upload.spec.ts(5 项,修复前必失败)与
test/scenes-degradation.spec.ts(6 项); - 发布产物解压后
npm ci --omit=dev+node dist/main.js实测打印
应用版本 v0.7.3(与/health、管理端左下角同源)。
部署与部署后自检
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/opendance-web-v0.7.3.tar.gz curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/SHA256SUMS sha256sum -c SHA256SUMS tar -xzf opendance-web-v0.7.3.tar.gz && cd opendance-web-v0.7.3 sudo bash deploy/install.sh # 部署后必须「可核对」: curl -s http://<服务器地址>:3000/health | grep -o '"version":"[^"]*"' # 必须输出 0.7.3 # 场景子系统可用性(降级时也会如实显示原因,而不是把整站带崩): curl -s http://<服务器地址>:3000/health | python3 -m json.tool | grep -A3 '"scenes"' # 若 scenes 不可用,先诊断再决定是否补表: cd <APP_DIR>/web-server && set -a && . ../deploy/.env && set +a node scripts/diagnose-scenes.mjs数据库端到端验收(歌曲 → 动作 → 预处理 → 模型 → 审核 → 场景 → 目录导出):
API_BASE=http://<服务器地址>:3000 node web-server/test/smoke.mjs<服务器地址>是你们自己部署的服务端地址(部署方决定),不是被脱敏的域名。交付物校验和(可核对)
5d0f90ec6a1b58ad0beec92928c99467bc159c2720e3b058da7e588fdddda519 opendance-web-v0.7.3.tar.gz下载后:
curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/SHA256SUMS curl -fLO https://gitea.kasugano.cn/zijunchiang/opendance-web/releases/download/v0.7.3/opendance-web-v0.7.3.tar.gz sha256sum -c SHA256SUMS # 期望 OKDownloads