Files
cmshoppe/docs/update-check.md
T

129 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 版本检查接口契约(启动强制升级)
> 客户端在启动时请求版本接口,判断是否需要**强制升级**。本文是**服务端响应格式的权威契约**——字段以 `app/update_check.py` 的实际读取逻辑为准,服务端按此返回,避免格式漂移。
> T-544 已实现启动检查与浏览器下载引导;T-615 起增加自动安装所需的发布契约。T-615 只生成可验证发布包,客户端下载与替换由后续任务实现。
## 一、接口
- 客户端在 `main()` 启动流程里、进主界面之前请求(`app/gui/__init__.py` 的 `_run_startup_update_gate` → `app/update_check.py`)。
- URL 硬编码于 `app/version.py`:
```
APP_UPDATE_CHECK_URL = "https://cm.833729.com/api/v1/client/releases/latest?platform=windows"
```
- 方法:`GET`,请求头 `Accept: application/json`、`User-Agent: cmshopee/<版本>`。
- 客户端当前版本见 `app/version.py` 的 `APP_VERSION`。
## 二、客户端读取的字段(`update_check.parse_update_info`)
响应是一个 JSON 对象。T-544 兼容字段仍可位于顶层或 `release` 子对象;自动安装元数据由 `app/update_installer.py` 做第二层严格校验,生产服务应把同一版本的全部字段放进同一个 `release` 对象。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `version` / `latest_version` | string | 最新版本号。客户端取 `payload.latest_version` 或 `release.version`。**`latest_version` 与 `min_supported_version` 至少要有一个**,否则客户端判为"接口缺字段"、按失败放行 |
| `force_update` | bool | 是否强制升级。`true`/`1`/`yes`/`y`/`on`(大小写不敏感)都识别为真 |
| `min_supported_version` | string | 最低支持版本;本地低于它一律强制 |
| `download_url` | string(URL) | 安装包外链;优先 HTTPS,T-623 临时兼容任意公网 HTTP/HTTPS 地址 |
| `sha256` | string | zip 的 SHA-256;自动安装时必须是 64 位十六进制且不可为空 |
| `size_bytes` | integer | zip 的准确字节数;自动安装时必须大于 0 |
| `release_notes` / `message` | string | 升级说明,显示在强制升级弹窗里。客户端取 `message` 或 `release_notes` |
| `published_at` | string | 服务端发布时间;客户端当前不参与强制判定 |
`package_format`、`updater_protocol`、`min_updater_protocol` 不是 cmhub 版本接口字段。客户端使用内置 `cmshopee-portable-v1` 和当前更新器协议构造安装元数据,下载后再以包内 `package-manifest.json` 验证真实格式和协议;不兼容的包仍会在替换程序前拒绝。
版本号比较用**语义化数字段比较**(`compare_versions`,逐段比数字),不是字符串字典序:`0.1.10 > 0.1.9`。
## 三、强制规则(`is_forced_update`)
满足**任一**即判为强制:
1. `force_update = true` **且** 本地版本 `<` `latest_version`;
2. 本地版本 `<` `min_supported_version`。
两者都不满足 → **非强制**。
## 四、客户端行为(T-618)
- **强制且自动安装元数据完整**:弹模态进度窗口,显示中文阶段、下载百分比/字节数和发布说明;点击「立即升级」后在工作线程下载、校验和暂存,再启动独立更新器并退出旧程序。更新器完成事务替换后自动启动新版。
- **强制但元数据不完整,或下载/校验/更新器启动失败**:继续阻断主窗口,只允许「重试」或「退出程序」,不能降级放行旧版,也不再打开浏览器让用户手工覆盖。
- **同一版本和zip hash曾因新版早期崩溃回滚**:命中本地失败版本熔断,不重复自动安装;仍保持强制阻断,提示等待管理员发布不同hash的修复包/更高版本,或手动安装。
- **非强制**:**不弹任何提示**,直接进主界面(当前无"温和可跳过提示"分支;如需另立任务)。
- **失败放行**:接口断网、超时、返回非法 JSON、缺 `latest_version`/`min_supported_version` 时,客户端记诊断日志(`data/logs/cmshopee.log`,`step=startup_update_check`「已允许继续使用」)并**放行**,不因服务器故障导致全员打不开。
T-616 已实现安全暂存层,T-623 为兼容对象存储、CDN 和文件分发服务外链,临时允许任意公网 HTTP/HTTPS 下载地址及跨域、跨协议重定向。初始地址、每次跳转和最终响应都会拒绝本机、内网和非 HTTP(S) 目标;下载仍流式写入安装目录 `.cmshopee-update/`,并严格校验zip声明大小、SHA-256和包内manifest。任一步失败都不修改当前程序或 `data/`。
T-617 已提供独立无控制台更新器和事务回滚能力:更新器从系统临时目录运行,旧主程序退出后才切换程序根项目,并在新版进程无法创建时恢复旧版。T-618 已将其接入启动强制升级进度窗口。
## 五、发版约定(服务端据此控制)
自动安装使用的全部字段必须放在同一个 `release` 对象内,不得把版本取自一个对象、hash 取自另一个对象。构建脚本生成的 `release/release-metadata.json` 提供版本、zip SHA-256 和准确大小;发布人员录入公网 HTTP/HTTPS `download_url`、强制策略和中文发布说明,不得手工改写 hash 或大小。正式发布仍应优先使用 HTTPS;HTTP 只用于外链暂时无法提供 HTTPS 的兼容期。
| 想要的效果 | 服务端返回 |
| --- | --- |
| **强制升到最新**(方案 A) | `release.force_update: true` + `release.version` 高于要淘汰的客户端版本 |
| **强制淘汰旧版**(方案 B) | `min_supported_version` 设为要淘汰之上的版本(顶层或 `release` 里都可)|
| **不强制** | `force_update`/`min_supported_version` 都不给 → 客户端不弹(当前不提示)|
## 六、示例响应
### 强制升级(方案 A,推荐)
```json
{
"platform": "windows",
"release": {
"version": "0.1.1",
"download_url": "https://cm.833729.com/media/downloads/%E8%9D%A6%E7%9A%AE%E5%9C%88%E5%84%AA%E5%8C%96%E5%8A%A9%E6%89%8B0.1.1.zip",
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"size_bytes": 123456789,
"release_notes": "优化了ai模块的生图的功能",
"published_at": "2026-07-08T14:30:26.935549+08:00",
"force_update": true
}
}
```
效果:本地 `0.1.0` < `0.1.1` 且 `force_update=true` → 强制弹窗、必须升级。
### 强制淘汰旧版(方案 B)
```json
{
"platform": "windows",
"min_supported_version": "0.1.1",
"release": {
"version": "0.1.1",
"download_url": "https://cm.833729.com/media/downloads/...0.1.1.zip",
"release_notes": "优化了ai模块的生图的功能"
}
}
```
效果:本地低于 `0.1.1` 的一律强制升级。
### 不强制(有新版但不逼升)
```json
{
"platform": "windows",
"release": {
"version": "0.1.1",
"download_url": "https://cm.833729.com/media/downloads/...0.1.1.zip",
"release_notes": "优化了ai模块的生图的功能"
}
}
```
效果:客户端解析成功但判为非强制 → **当前不弹提示**,直接进主界面。
## 七、注意
- 服务端返回 `force_update`/`min_supported_version` 属**本仓库外的服务端配置**;客户端代码(`app/update_check.py`/`app/version.py`/启动流程)已按本契约实现,**发强制版不需要改客户端**。
- `download_url` 里的中文可用 URL 编码(如 `%E8%9D%A6...`),系统浏览器能正确打开。
- 版本检查接口 `APP_UPDATE_CHECK_URL` 必须保持受信任 HTTPS;只有它返回的 `download_url` 可以在 T-623 兼容期使用公网 HTTP 外链。客户端不提供手工输入下载地址或关闭校验的入口。
- 若将来要"非强制也温和提示(可跳过、不阻断)",需在客户端加一个非强制分支,另立任务。
- 空 `sha256` 只兼容 T-544 的人工下载引导,绝不能进入自动安装。自动安装无论使用 HTTP 还是 HTTPS,都必须同时校验接口 `size_bytes`、整包 SHA-256,以及客户端内置格式/协议对应的包内manifest。
- `manifest_signature` 与 `signature_algorithm` 是预留字段;当前未启用数字签名,不能将 SHA-256 描述为发布者身份认证。
## 八、引导版本与灰度发布
仍只有T-544“浏览器下载”能力的旧客户端无法凭空获得独立更新器,必须先人工覆盖一个同时包含T-615至T-619代码和 `cmshopee-updater.exe` 的引导版本。后续自动发布先以非强制方式灰度确认接口字段、下载和manifest,再开启 `force_update` 或提高 `min_supported_version`。包内manifest的 `updater_protocol` / `min_updater_protocol` 必须与引导版本兼容,cmhub 版本接口无需重复返回。
更新器启动新版后等待健康标记:`process_started` 表示基础导入、Qt和版本核对完成;`main_window_ready` 表示数据目录、必要初始化和主窗口显示完成,此时才清理成功备份;`environment_blocked` 表示数据目录、配置或Chrome等本地环境需用户处理,保留新版且不误回滚。无已知标记、版本不符、早期退出或健康等待超时会恢复旧版并写失败版本熔断记录。