feat: 实现 Client 在线更新与安全回退 (#93)

This commit is contained in:
chengma
2026-08-10 12:32:39 +08:00
parent c24fac964e
commit 6d6829e374
14 changed files with 1609 additions and 18 deletions
+20
View File
@@ -145,6 +145,8 @@ client/
- Repository 封装 SQLite,界面和自动化代码不得直接拼接业务 SQL。
- PDD Adapter 封装设备连接、页面识别、采集和采购。
- ArtifactStore 保存失败截图、无障碍 XML 和结构化诊断文件。
- `UpdateService` 只负责 HTTPS 清单、下载校验和安全暂存;正在运行的主程序不替换
自身,目录替换与回退只由下一次启动的 `Launcher.exe` 执行。
## 5. 线程模型
@@ -161,6 +163,10 @@ Qt 主线程
结果提交工作线程或同一任务线程的独立队列
└── Outbox 重试,不重复执行 PDD 操作
更新工作线程
├── 检查 HTTPS 清单
└── 下载、SHA256 校验和安全解压到 data/update/
```
- `[必须]` QWidget 只能在 Qt 主线程创建和访问。
@@ -168,6 +174,8 @@ Qt 主线程
- `[必须]` 后台信号只传递不可变数据、稳定编号或轻量视图模型。
- `[必须]` 点“停止获取”后不再领取新任务,当前任务在定义的安全点退出。
- `[建议]` 关闭窗口时应选择停止、等待或后台继续;MVP 默认安全停止并持久化状态。
- `[必须]` 更新检查和下载使用独立 `QObject + moveToThread` Worker;下载完成只提示
下次启动生效,不得为了更新强制中断采集或采购任务。
### 5.1 Worker 模板(项目统一写法,照抄即可)
@@ -282,6 +290,18 @@ def _on_finished(self, remote_task_id: str, result) -> None:
注意:**断开信号只是不更新界面,任务的数据该落库还是要落库**。落库由应用层负责,和界面在不在没关系——这正是"结果先写本地再提交 Admin"的意义,见 §8。
### 5.3 在线更新启动顺序
```text
主程序:HTTPS 清单 → 用户确认 → 下载并校验 → data/update/app.new + pending.json
Launcher:确认主程序未运行 → app 改名 app.old → app.new 改名 app → 启动主程序
主程序:窗口成功创建 → 写 healthy.json
Launcher:健康标记正确则完成;提前退出则恢复 app.old
```
更新 ZIP 只允许 `app/` 内容,拒绝绝对路径、`..`、反斜杠路径和符号链接。Launcher
不联网、不处理凭据,也不自更新。
## 6. 任务引擎状态
任务协调器状态: