feat: 重构更新流程 — 无更新不抛异常、用户决定下载、更新详情展示(md文件中的)

【核心重构】
  - getLatestVersion() 不再 throw Error,无更新时返回 { version: APP_VERSION }
  - checkForUpdates() 先自行预检 → 无更新直发 IPC,有更新才交 electron-updater
  - 移除 NO_UPDATE_MESSAGE 常量及所有字符串匹配拦截代码
  - HeiXiuProvider 增加 500ms TTL 缓存,避免预检+electron-updater 重复请求 API

  【用户体验】
  - 检查到新版本后不再自动下载,展示更新内容供用户决定
  - 新增"下载更新"按钮(与"安装更新"分离为两步操作)
  - 设置页新增"查看详情"弹窗,Markdown 格式化渲染更新日志
  - available / downloading / downloaded 三个状态 UI 独立展示

  【Bug 修复】
  - 测试服务器版本排序:字符串序 → 语义版本序(_version_key),0.0.10 正确 > 0.0.9
  - 版本比较:!= → <(_version_key),防止高版本误判为有更新
  - get_best_release fallback 同样改为语义版本排序
  - Windows cmd set 命令尾部空格 → Invalid URL(.trim() 修复)
  - electron-updater 'error' 事件中拦截 NO_UPDATE_MESSAGE → UPDATE_NOT_AVAILABLE

  【文档更新】
  - CHANGELOG.md、PROJECT.md、UpdateA.md 同步更新架构图和流程说明
This commit is contained in:
2026-06-04 18:31:52 +08:00
parent b55c2fdd2e
commit 6204c14b88
37 changed files with 1908 additions and 648 deletions

180
test-server/README.md Normal file
View File

@@ -0,0 +1,180 @@
# HeiXiu 更新服务器 — 后端对接文档
> 本文档供后端程序员阅读和实现。
---
## 快速启动测试服务器
```bash
cd test-server
pip install fastapi uvicorn
python server.py --release-dir ../release --port 8000
```
启动后访问:
- API 文档Swagger`http://localhost:8000/docs`
- 健康检查:`http://localhost:8000/health`
---
## API 端点
所有请求为 `GET`,无鉴权。
### 1. `GET /api/v1/update/check` — 版本检查
客户端启动后调用,决定是否提示用户更新。
**请求参数Query String**
| 参数 | 类型 | 必填 | 示例 | 说明 |
|------|------|:--:|------|------|
| `platform` | string | 是 | `win32` | `win32` / `darwin` / `linux` |
| `version` | string | 是 | `0.0.3` | 客户端当前版本号(三段式 semver |
| `edition` | string | 否 | `personal` | `personal` / `enterprise`,默认 `personal` |
**响应 — 有更新时:**
```json
{
"code": 0,
"data": {
"hasUpdate": true,
"latestVersion": "0.0.4",
"downloadUrl": "https://heixiu.oss-cn-hangzhou.aliyuncs.com/releases/0.0.4/xxx-Setup.exe",
"fileSize": 113581841,
"sha512": "Base64...",
"blockMapUrl": "https://heixiu.oss-cn-hangzhou.aliyuncs.com/releases/0.0.4/xxx-Setup.exe.blockmap",
"blockMapSize": 120256,
"changelog": "## 0.0.4\n\n- 日志记录\n- 增量更新",
"releaseDate": "2026-06-04",
"forceUpdate": false,
"minimumVersion": "0.0.0"
}
}
```
**响应 — 无更新时:**
```json
{
"code": 0,
"data": {
"hasUpdate": false
}
}
```
**字段说明:**
| 字段 | 类型 | 必填 | 说明 |
|------|------|:--:|------|
| `downloadUrl` | string | 是 | 安装包 HTTPS 直链 |
| `fileSize` | number | 是 | 安装包字节数 |
| `sha512` | string | 是 | 安装包 SHA512 Base64 |
| `blockMapUrl` | string | 否 | blockmap 文件 URL缺失时客户端全量下载 |
| `blockMapSize` | number | 否 | blockmap 文件字节数(`> 0` 时客户端启用增量下载) |
| `changelog` | string | 否 | Markdown 格式更新日志 |
| `releaseDate` | string | 否 | 发布日期YYYY-MM-DD |
| `forceUpdate` | boolean | 否 | 是否强制更新(`true` 时用户不可跳过) |
| `minimumVersion` | string | 否 | 最低兼容版本(低于此版本的客户端必须更新) |
> **增量更新说明**`blockMapUrl` + `blockMapSize` 为可选字段。客户端检测到 `blockMapSize > 0` 时自动启用增量下载(仅下载变更区块,节省 30%-70% 流量)。不传或为 `null` 时客户端全量下载。
---
### 2. `POST /api/v1/releases` — 发布新版本(需要鉴权)
```http
POST /api/v1/releases
Authorization: Bearer <UPDATE_API_KEY>
Content-Type: application/json
```
**请求体:**
```json
{
"platform": "win32",
"edition": "personal",
"latestVersion": "0.1.0",
"downloadUrl": "https://heixiu.oss-cn-hangzhou.aliyuncs.com/releases/0.1.0/xxx.exe",
"fileSize": 112910987,
"sha512": "Base64...",
"blockMapUrl": "https://heixiu.oss-cn-hangzhou.aliyuncs.com/releases/0.1.0/xxx.exe.blockmap",
"blockMapSize": 152340,
"changelog": "## 0.1.0\n\n- 新功能 A\n- 修复 B",
"releaseDate": "2026-06-04",
"forceUpdate": false,
"minimumVersion": "0.0.0"
}
```
---
## 数据库表结构
```sql
CREATE TABLE releases (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
platform VARCHAR(10) NOT NULL COMMENT 'win32 / darwin / linux',
edition VARCHAR(10) NOT NULL COMMENT 'personal / enterprise',
version VARCHAR(20) NOT NULL COMMENT '三段式 semver',
file_url VARCHAR(500) NOT NULL COMMENT '安装包 OSS HTTPS 地址',
file_size BIGINT NOT NULL COMMENT '安装包字节数',
sha512 VARCHAR(128) NOT NULL COMMENT '安装包 SHA512 Base64',
blockmap_url VARCHAR(500) COMMENT 'blockmap OSS 地址(可为空)',
blockmap_size BIGINT COMMENT 'blockmap 文件字节数',
changelog TEXT COMMENT 'Markdown 格式更新日志',
force_update TINYINT(1) DEFAULT 0,
min_version VARCHAR(20) DEFAULT '',
release_date DATE NOT NULL,
status VARCHAR(10) DEFAULT 'draft' COMMENT 'draft / published / deprecated',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_platform_edition_version (platform, edition, version),
INDEX idx_platform_edition_status (platform, edition, status)
);
```
---
## 更新检查逻辑(参考实现)
```
GET /api/v1/update/check?platform=win32&version=0.0.3&edition=personal
1. 查询最新 published 版本:
SELECT * FROM releases
WHERE platform = 'win32'
AND edition = 'personal'
AND status = 'published'
ORDER BY version DESC
LIMIT 1
2. 比较版本号:
- 请求 version >= 最新 version → hasUpdate = false
- 请求 version < 最新 version → hasUpdate = true
3. 版本比较建议用 semver 规则major.minor.patch
```
---
## 文件托管OSS
- 安装包和 `.blockmap` 文件托管在阿里云 OSS允许公开读取
- 路径约定:`releases/{version}/{filename}`
- 客户端通过 `downloadUrl` 直接下载,不经过后端 API
---
## 后端实现清单
- [ ] 部署 `GET /api/v1/update/check`
- [ ] 部署 `POST /api/v1/releases`Bearer Token 鉴权)
- [ ] 创建 `releases`
- [ ] 配置 OSS 公开读取 + HTTPS
- [ ] 可选API Key 白名单 + 限流