fix: OTA 更新需用户同意、下载完整性与暂存区管理

- 安装同意标记:仅「下次启动安装」写入,main.rs 凭标记才自动安装,
  跳过确认对话框不会再被强制升级;对话框新增「暂不更新」(删除暂存包)
- 下载完整性:API 提供大小却未下满/超量时报错(read 返回 0 无法
  区分干净结束与连接截断);失败路径统一清理 tmp 文件
- 版本比较遵循 semver 预发布语义(1.0.0-beta.2 不比 1.0.0 新);
  暂存文件名按尾部锚点解析,预发布后缀不再丢失导致重复下载
- 多版本暂存并存时取最新(readdir 顺序无序);下载完成后清理旧版本残留
- install_staged:spawn 失败(杀毒锁文件)自动恢复旧版本并如实报告回滚结果
- agent 加整体 10 分钟超时;cleanup_old 大小写不敏感、跳过近期 tmp
  避免误删并行实例正在写入的文件
- 设置对话框:下载进度条传百分比(原 0~1 小数只显示 1%);
  立即安装失败显示具体错误;Sentry release 与更新检查同源版本号
This commit is contained in:
2026-09-29 10:33:28 +08:00
parent f1a7c9eb45
commit 5dc1a8cc0b
3 changed files with 259 additions and 62 deletions
+28 -7
View File
@@ -233,15 +233,15 @@ impl SettingsDialog {
.primary()
.xsmall()
.on_click(move |_, window, cx| {
if update::install_staged(&staged_now).is_ok() {
cx.quit();
} else {
if let Err(e) = update::install_staged(&staged_now) {
window.push_notification(
Notification::error(
"安装失败,请重试",
),
Notification::error(format!(
"安装失败:{e}"
)),
cx,
);
} else {
cx.quit();
}
}),
)
@@ -251,6 +251,10 @@ impl SettingsDialog {
.outline()
.xsmall()
.on_click(cx.listener(|this, _, window, cx| {
// 写入同意标记:下次启动据此自动安装
if let UpdateUi::ReadyToInstall(staged) = &this.update {
update::mark_install_consent(&staged.version);
}
this.update = UpdateUi::Idle;
window.push_notification(
Notification::info(
@@ -260,6 +264,23 @@ impl SettingsDialog {
);
cx.notify();
})),
)
.child(
Button::new("upd-discard")
.label("放弃此次更新")
.outline()
.xsmall()
.on_click(cx.listener(|this, _, window, cx| {
if let UpdateUi::ReadyToInstall(staged) = &this.update {
update::discard_staged(staged);
}
this.update = UpdateUi::Idle;
window.push_notification(
Notification::info("已删除暂存的更新包"),
cx,
);
cx.notify();
})),
),
)
}
@@ -283,7 +304,7 @@ impl SettingsDialog {
.gap_1()
.child(
gpui_kit::component::progress::Progress::new("update-progress")
.value(pct),
.value(pct * 100.),
)
.child(
div()