diff --git a/contracts/rest-api.yaml b/contracts/rest-api.yaml index 6964940..2170b51 100644 --- a/contracts/rest-api.yaml +++ b/contracts/rest-api.yaml @@ -940,4 +940,96 @@ components: songs: { type: array, items: { $ref: '#/components/schemas/Song' } } motions: { type: array, items: { $ref: '#/components/schemas/Motion' } } models: { type: array, items: { $ref: '#/components/schemas/Model' } } + scenes: + type: array + description: 已发布场景(rest-api 0.5.0 起随目录下发;结构见 data-models.md 7) + items: { $ref: '#/components/schemas/Scene' } defaultModelId: { type: integer, format: int64, nullable: true } + + Scene: + allOf: + - $ref: '#/components/schemas/SourceFields' + - type: object + properties: + id: { type: integer, format: int64 } + name: { type: string } + glbUrl: { type: string, nullable: true, description: 场景 GLB 下载地址 } + thumbnailUrl: { type: string, nullable: true } + fileSize: { type: integer, nullable: true } + fileSha256: { type: string, nullable: true } + conversionNote: + type: string + nullable: true + description: 由 .zip/.pmx/.fbx 转换而来时的说明;直接上传 GLB 为 null + config: + allOf: [{ $ref: '#/components/schemas/SceneConfig' }] + nullable: true + description: 物理 / 环境 / 出生点 / 相机;服务端只存参数,仿真在客户端 + stats: + type: object + nullable: true + description: 场景 GLB 分析(面数 / 网格 / 材质 / warnings) + status: { $ref: '#/components/schemas/PublishStatus' } + createdAt: { type: string, format: date-time } + updatedAt: { type: string, format: date-time } + + SceneConfig: + type: object + description: >- + data-models.md 7.1 冻结结构。服务端入库时对每项做边界收敛 + (越界夹紧、非法枚举回退默认值),客户端拿到的参数一定可解释。 + properties: + physics: + type: object + properties: + gravity: + type: object + description: 米/秒^2,各分量 ±200 + properties: + x: { type: number } + y: { type: number } + z: { type: number } + wind: + type: object + properties: + base: { $ref: '#/components/schemas/Vec3' } + gustAmplitude: { type: number, description: 0~100 } + gustFrequency: { type: number, description: Hz,0.01~5 } + gustDirection: { $ref: '#/components/schemas/Vec3' } + space: { type: string, enum: [world, local] } + ground: + type: object + properties: + friction: { type: number, description: 0~1 } + restitution: { type: number, description: 0~1 } + slopeLimit: { type: number, description: 0~89 度 } + colliders: { type: string, enum: [auto, mesh, none] } + environment: + type: object + properties: + ambientColor: { type: string, description: '#RRGGBB' } + ambientIntensity: { type: number, description: 0~4 } + fogDensity: { type: number, description: 0~1,0=关闭 } + spawnPoints: + type: array + maxItems: 16 + items: + type: object + properties: + x: { type: number } + y: { type: number } + z: { type: number } + yaw: { type: number, description: 朝向(度,绕 Y 轴) } + camera: + type: object + properties: + mode: { type: string, enum: [follow, fixed, orbit] } + distance: { type: number, description: 0.5~50 } + height: { type: number, description: 0~20 } + + Vec3: + type: object + properties: + x: { type: number } + y: { type: number } + z: { type: number } diff --git a/deploy/proxy/README.md b/deploy/proxy/README.md index 5b36ae5..62ab205 100644 --- a/deploy/proxy/README.md +++ b/deploy/proxy/README.md @@ -204,6 +204,7 @@ curl -i http://<反代地址>/api/catalog/version | 客户端接口全 404 | 把客户端的转发规则指到了管理端口之外,或误把 `/api` 前缀重写掉;客户端应转发到软件 API 端口 | | 管理页面 404 | 把浏览器的转发规则指到了**软件 API 端口**(该端口不提供管理页面,这是有意设计);改指 `ADMIN_PORT` | | 两个端口都转发到同一条规则 | 若确实想合并两个端口,设置 `ADMIN_PORT=PORT` 走单端口模式,而不是让反代去猜 | +| **Gitea 的 Release 附件上传 413** | 这是**另一台站点**(托管 Gitea 的 IIS),本服务的 `UPLOAD_MAX_BYTES` 管不到它;见第九节 | ## 八、还没有反代时:直连后端怎么访问 @@ -226,3 +227,91 @@ bash deploy/check-access.sh /opt/opendance # 指定安装目录 脚本会打印 `.env` 中的 `HOST`/`PORT`、实际监听地址(重点看是否只监听 `127.0.0.1`)、回环与对外 IP 两次自测结果、80/443 上有没有反代、 firewalld / ufw / iptables 的放行情况,并直接给出修复命令。 + +--- + +## 九、Gitea 站点的附件上传上限(Windows 客户端整包必须放开) + +> 本节与第一~五节是**两个不同的站点**:前者是本 Web 服务的反代,后者是托管 +> **Gitea**(源码仓库 + Release 附件)的站点。Windows 客户端的发布整包走 Gitea, +> 因此**必须**单独放开 Gitea 站点的上限。 + +### 9.1 实测结论 + +| 上传体积 | 结果 | +|--|--| +| 14 MB | 通过(HTTP 201) | +| 30.5 MB | **失败 HTTP 413**(IIS「请求实体过大」页面) | +| 40 MB | **失败 HTTP 413** | + +→ 默认上限就是 **IIS 的 `maxAllowedContentLength = 30,000,000` 字节(≈28.6 MiB)**。 +Windows 客户端整包约 38 MB(`OpenDance.exe` ≈104 MB 未压缩 + `OpenDance.pck`), +早先因此被拆成 `zip.part0/1/2`(每卷 13 MiB)才传上去 —— 用户拿到的是 +**无法直接解压的碎片**,必须自己拼接,属于交付缺陷。 + +### 9.2 正确做法:放开 Gitea 站点上限到 256 MB + +1. **IIS**(托管 Gitea 的站点根目录 `web.config`): + + ```xml + + + + + + + + + + + + ``` + + `uploadReadAheadSize` 必须一起改(SSL 场景下默认仅 48 KB,会中途失败)。 + +2. **ARR**(服务器级,不是站点级)在 `applicationHost.config` 中同步放宽请求体上限: + + ```xml + + + + + + + + ``` + + 并在 IIS 管理器 → Application Request Routing Cache → Server Proxy Settings + 中确认请求体上限(`maxRequestBytes`)≥ `268435456`。 + +3. **Gitea 自身** `app.ini`: + + ```ini + [attachment] + ; 默认通常为 4~32 MB,必须一起放大,否则 IIS 放行了 Gitea 仍会拒绝 + MAX_SIZE = 256 + ``` + +4. **若 Gitea 前面还有 nginx**(IIS 之外或之内): + + ```nginx + client_max_body_size 256m; + proxy_read_timeout 300s; + proxy_send_timeout 300s; + ``` + +5. 改完执行 `iisreset /noforce`(或只重启站点),再按下节复验。 + +### 9.3 复验方法 + +```bash +# 造一个 40 MB 文件上传到 Gitea 的附件接口,预期 HTTP 201(不再是 413) +head -c 40000000 /dev/urandom > /tmp/probe.bin +curl -i -X POST \ + -H "Authorization: token " \ + -F "file=@/tmp/probe.bin" \ + "https:///api/v1/repos///releases//assets?name=probe.bin" +``` + +在放开上限之前,**不要**用分卷绕过:Windows 端 `build/package-release.sh` +会拒绝生成 `.partN`,超限时直接告警并要求先放宽本节的配置。