升级成功后重启应用程序

This commit is contained in:
zqm
2026-04-13 12:50:30 +08:00
parent e8e45ba012
commit 9724a4c945

View File

@@ -19,7 +19,7 @@ fn init_log_file() {
Err(_) => return,
};
let log_dir = match exe_path.parent() {
Some(d) => d.join("Log"),
Some(d) => d.join("Updater").join("Log"),
None => return,
};
@@ -143,6 +143,7 @@ use std::path::PathBuf;
use std::pin::Pin;
use std::process::Command;
use std::io::Write as StdWrite;
use std::io::Seek;
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
use cube_lib::websocket::{WebSocketClient, WebSocketConfig};
@@ -597,9 +598,11 @@ fn handle_file_chunk(
let mut ctx = ctx.download_state.lock().unwrap();
// 如果是新文件或 offset=0重置状态
// 只有文件名变化才重置(开始下载新文件)
// 注意:不要用 offset==0 判断是否重置!
// offset>0 表示续传server 从该偏移继续发块),不应重置 tmp 文件
let need_reset = match ctx.as_ref() {
Some(s) => &s.filename != &final_filename || offset == 0,
Some(s) => &s.filename != &final_filename,
None => true,
};
if need_reset {
@@ -618,23 +621,46 @@ fn handle_file_chunk(
let data_dir = get_updater_data_dir();
let temp_path = data_dir.join(format!("{}.tmp", final_filename));
// 创建临时文件(截断
match File::create(&temp_path) {
Ok(file) => {
*ctx = Some(DownloadState {
filename: final_filename.clone(),
offset: 0,
temp_path: Some(temp_path),
file: Some(file),
});
}
Err(_) => {
if debug {
eprintln!("[下载] 无法创建临时文件: {}", filename);
// 续传tmp 文件已存在,以追加方式打开(保留已有数据
// 新下载tmp 文件不存在,用 File::create 创建(截断模式)
let (file, resume_offset) = if temp_path.exists() {
use std::fs::OpenOptions;
match OpenOptions::new().write(true).append(true).open(&temp_path) {
Ok(f) => {
let current_size = f.metadata().map(|m| m.len()).unwrap_or(0);
if debug {
eprintln!("[下载] 续传:追加打开 {:?}, 当前大小={}", temp_path, current_size);
}
let mut file = f;
file.seek(std::io::SeekFrom::Start(current_size)).ok();
(file, current_size)
}
Err(e) => {
if debug {
eprintln!("[下载] 无法追加打开临时文件 {}: {}", filename, e);
}
return None;
}
return None;
}
}
} else {
// 新下载,截断创建
match File::create(&temp_path) {
Ok(file) => (file, 0u64),
Err(e) => {
if debug {
eprintln!("[下载] 无法创建临时文件 {}: {}", filename, e);
}
return None;
}
}
};
*ctx = Some(DownloadState {
filename: final_filename.clone(),
offset: resume_offset,
temp_path: Some(temp_path),
file: Some(file),
});
}
// 解码并追加数据
@@ -1856,13 +1882,31 @@ async fn run_updater(debug_mode: bool) -> bool {
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
// 收到消息日志(始终记录)
let actual_data = data.get("Data").unwrap_or(&serde_json::Value::Null);
let data_str = serde_json::to_string(actual_data).unwrap_or_else(|_| "{}".to_string());
log_print!("{} 收到消息:{{\"Type\":{},\"Data\":{}}}",
ts,
serde_json::to_string(&msg_type).unwrap_or_default(),
data_str
);
// FileChunk 跳过完整 Data 序列化Data 中含约40KB base64同步阻塞tokio runtime导致30秒延迟
if msg_type == "FileChunk" {
let filename = data.get("Data")
.and_then(|v| v.get("filename"))
.and_then(|v| v.as_str())
.unwrap_or("?");
let offset = data.get("Data")
.and_then(|v| v.get("offset"))
.and_then(|v| v.as_u64())
.unwrap_or(0);
let is_last = data.get("Data")
.and_then(|v| v.get("is_last"))
.and_then(|v| v.as_bool())
.unwrap_or(false);
log_print!("{} 收到消息:{{\"Type\":\"FileChunk\",\"filename\":\"{}\",\"offset\":{},\"is_last\":{}}}",
ts, filename, offset, is_last);
} else {
let actual_data = data.get("Data").unwrap_or(&serde_json::Value::Null);
let data_str = serde_json::to_string(actual_data).unwrap_or_else(|_| "{}".to_string());
log_print!("{} 收到消息:{{\"Type\":{},\"Data\":{}}}",
ts,
serde_json::to_string(&msg_type).unwrap_or_default(),
data_str
);
}
// 收到 welcome 后,重置状态并从头开始执行流程
if msg_type == "welcome" {
@@ -2379,11 +2423,23 @@ async fn run_updater(debug_mode: bool) -> bool {
}
break;
}
} else {
} else {
// ========== BootLoader/Updater 的 FileChunk 处理 ==========
let completed = handle_file_chunk(&ctx_clone, data_obj, debug_msg);
// 只处理 Updater 下载完成BootLoader 由 DownloadComplete 统一处理,避免重复)
if let Some(ref completed_file) = completed {
// BootLoader 下载完成推进到阶段2
if completed_file == "BootLoader.exe" {
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
*ctx_clone.current_phase.lock().unwrap() = UpdatePhase::Updater;
log_print!("{} [阶段2] 检查 Updater...", ts);
let msg_str = format!(
r#"{{"Type":"GetFileVer","Data":{{"DeviceNumber":"{}","file_list":["Updater.exe"]}}}}"#,
device_number
);
log_print!("{} 发送消息:{}", ts, msg_str);
sender.send(msg_str);
}
// Updater 下载完成:启动 BootLoader
if completed_file == "Updater.new.exe" {
if !updater_downloaded_clone2.load(std::sync::atomic::Ordering::SeqCst) {
updater_downloaded_clone2.store(true, std::sync::atomic::Ordering::SeqCst);
@@ -2394,6 +2450,18 @@ async fn run_updater(debug_mode: bool) -> bool {
schedule_bootloader_launch(debug_msg, shutdown_tx_arc_clone.clone());
}
}
} else {
// 非最后一块主动请求下一块BootLoader/Updater 流式下载需客户端驱动)
let is_last = data_obj.get("is_last").and_then(|v| v.as_bool()).unwrap_or(false);
let chunk_offset = data_obj.get("offset").and_then(|v| v.as_u64()).unwrap_or(0);
let file_size = data_obj.get("file_size").and_then(|v| v.as_u64()).unwrap_or(0);
let chunk_size = 4096u64;
if !is_last {
let next_offset = chunk_offset + chunk_size;
if next_offset < file_size {
request_download(&sender, filename, next_offset);
}
}
}
}
}