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
+21 -8
View File
@@ -13,19 +13,32 @@ fn init_sentry() -> sentry::ClientInitGuard {
sentry::init(
sentry::ClientOptions::new()
.dsn(SENTRY_DSN)
.release(format!("mqttx@{}", env!("CARGO_PKG_VERSION"))),
// 与更新检查用同一版本来源(尊重 MQTTX_VERSION_OVERRIDE),保持一致
.release(format!("mqttx@{}", update::current_version())),
)
}
fn main() {
// OTA 收尾:清理遗留文件;若暂存区有待安装的新版本(用户上次同意安装),
// 在进入 UI 前完成自替换并重启。
// OTA 收尾:清理遗留文件;若暂存区有待安装的新版本且用户已同意
// (「下次启动安装」),在进入 UI 前完成自替换并重启。
update::cleanup_old();
if let Some(staged) = update::load_staged()
&& update::install_staged(&staged).is_ok()
{
// 新进程已拉起,当前进程立即退出
std::process::exit(0);
if let Some(staged) = update::load_staged() {
if update::install_consent_matches(&staged.version) {
match update::install_staged(&staged) {
Ok(()) => {
// 新进程已拉起,当前进程立即退出
std::process::exit(0);
}
Err(_) => {
// 安装失败:清除同意标记,继续正常启动,
// 由应用内的更新检查重新弹窗询问。
update::clear_install_consent();
}
}
} else {
// 暂存包存在但用户未同意安装(例如跳过了确认对话框):
// 不做任何替换,等待应用内更新流程再次询问。
}
}
let _sentry_guard = init_sentry();