流程完成
This commit is contained in:
@@ -809,7 +809,12 @@ fn request_download_for_app(
|
||||
|
||||
|
||||
/// 从待下载队列取出一个文件发送(顺序下载)
|
||||
fn send_next_download(ctx: &Arc<UpdateContext>, sender: &cube_lib::websocket::MessageSender) {
|
||||
/// shutdown_tx: 进入 Complete 阶段后发送此信号断开连接
|
||||
fn send_next_download(
|
||||
ctx: &Arc<UpdateContext>,
|
||||
sender: &cube_lib::websocket::MessageSender,
|
||||
shutdown_tx: &std::sync::Arc<std::sync::Mutex<Option<tokio::sync::oneshot::Sender<()>>>>
|
||||
) {
|
||||
let mut queue = ctx.download_queue.lock().unwrap();
|
||||
if let Some((app_name, filename, offset, expected_md5)) = queue.pop_front() {
|
||||
// 记录当前下载的期望 MD5,供 DownloadComplete 校验
|
||||
@@ -822,8 +827,28 @@ fn send_next_download(ctx: &Arc<UpdateContext>, sender: &cube_lib::websocket::Me
|
||||
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
|
||||
let pending_apps = ctx.pending_allfile_apps.lock().unwrap();
|
||||
if pending_apps.is_empty() {
|
||||
log_print!("{} [下载] 所有应用文件下载完成,进入 Complete 阶段", ts);
|
||||
*ctx.current_phase.lock().unwrap() = UpdatePhase::Complete;
|
||||
|
||||
// 打印下载完成摘要
|
||||
let completed = ctx.app_completed_set.lock().unwrap();
|
||||
let mut app_summary: std::collections::HashMap<String, Vec<String>> = std::collections::HashMap::new();
|
||||
for key in completed.iter() {
|
||||
if let Some((app_name, filename)) = key.split_once('/') {
|
||||
app_summary.entry(app_name.to_string()).or_default().push(filename.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
log_print!("{} [下载] === 所有应用文件下载完成 ===", ts);
|
||||
for (app_name, files) in &app_summary {
|
||||
log_print!("{} [下载] {}: {} 个文件 ({})", ts, app_name, files.len(), files.join(", "));
|
||||
}
|
||||
log_print!("{} [下载] 文件保存在: {:?}", ts, get_updater_data_dir().join("Updater").join("UpGrade"));
|
||||
log_print!("{} [下载] ======================================", ts);
|
||||
|
||||
// 发送 shutdown 信号,断开连接返回主循环
|
||||
if let Some(tx) = shutdown_tx.lock().unwrap().take() {
|
||||
let _ = tx.send(());
|
||||
}
|
||||
} else {
|
||||
log_print!("{} [下载] 队列为空,等待 {} 个应用完成 AllFile 响应", ts, pending_apps.len());
|
||||
}
|
||||
@@ -881,15 +906,17 @@ fn handle_app_file_chunk(
|
||||
|
||||
// relative_path 已经是去掉 app_name/ 前缀的相对路径(如 "x64/SQLite.Interop.dll")
|
||||
// 直接用它构建路径,保留子目录信息
|
||||
let temp_path = get_updater_data_dir()
|
||||
// 注意:不能用 with_extension("tmp") 直接替换,因为会丢失原有扩展名!
|
||||
// 需要手动添加 .tmp 后缀
|
||||
let base_path = get_updater_data_dir()
|
||||
.join("Updater")
|
||||
.join("UpGrade")
|
||||
.join(app_name)
|
||||
.join(&relative_path)
|
||||
.with_extension("tmp");
|
||||
.join(&relative_path);
|
||||
let temp_path = PathBuf::from(format!("{}.tmp", base_path.to_string_lossy()));
|
||||
|
||||
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
|
||||
println!("{} [应用] 新文件: filename={}, tmp_path={:?}, parent_exists={}",
|
||||
log_print!("{} [应用] 新文件: filename={}, tmp_path={:?}, parent_exists={}",
|
||||
ts, filename, temp_path, temp_path.parent().map(|p| p.exists()).unwrap_or(false));
|
||||
|
||||
match File::create(&temp_path) {
|
||||
@@ -949,7 +976,14 @@ fn handle_app_file_chunk(
|
||||
|
||||
if let Some(ref temp) = temp_path {
|
||||
// final_path 是 temp_path 去掉 ".tmp" 后缀,直接在同一目录
|
||||
let final_path = temp.with_extension(""); // 去掉 .tmp 后缀
|
||||
// 注意:不能用 with_extension(""),因为它会替换原有扩展名!
|
||||
// 对于 "x86/SQLite.Interop.dll.tmp",with_extension("") 会得到 "x86/SQLite.Interop"(.dll 丢失!)
|
||||
let temp_str = temp.to_string_lossy();
|
||||
let final_path = if temp_str.ends_with(".tmp") {
|
||||
PathBuf::from(&temp_str[..temp_str.len() - 4])
|
||||
} else {
|
||||
temp.clone()
|
||||
};
|
||||
let _ = fs::create_dir_all(final_path.parent().unwrap());
|
||||
|
||||
// 重命名(同步操作,Windows 上不会异步)
|
||||
@@ -960,8 +994,8 @@ fn handle_app_file_chunk(
|
||||
}
|
||||
|
||||
let ts = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f");
|
||||
println!("{} [应用] is_last=true: filename={}, temp={:?}, final={:?}, rename_ok={}",
|
||||
ts, filename, temp, final_path, rename_ok);
|
||||
log_print!("{} [应用] 文件下载完成: filename={}, final_path={:?}, rename_ok={}, final_exists={}",
|
||||
ts, filename, final_path, rename_ok, final_path.exists());
|
||||
if debug {
|
||||
println!("{} [应用] {} 下载完成,共 {} 字节", ts, filename, final_offset);
|
||||
}
|
||||
@@ -1898,7 +1932,7 @@ async fn run_updater(debug_mode: bool) -> bool {
|
||||
};
|
||||
if should_start {
|
||||
*ctx_clone.is_downloading.lock().unwrap() = true;
|
||||
send_next_download(&ctx_clone, &sender);
|
||||
send_next_download(&ctx_clone, &sender, &shutdown_tx_arc_clone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1945,7 +1979,7 @@ async fn run_updater(debug_mode: bool) -> bool {
|
||||
}
|
||||
ctx_clone.app_completed_set.lock().unwrap().insert(format!("{}/{}", app_name, filename));
|
||||
log_print!("{} [FileChunk] 调用 send_next_download, queue_len={}", ts, queue_len);
|
||||
send_next_download(&ctx_clone, &sender);
|
||||
send_next_download(&ctx_clone, &sender, &shutdown_tx_arc_clone);
|
||||
} else {
|
||||
// 非最后一块,立即请求下一块(用 relative_path,不带 app_name/ 前缀)
|
||||
let next_offset = chunk_offset + chunk_size;
|
||||
@@ -2035,7 +2069,7 @@ async fn run_updater(debug_mode: bool) -> bool {
|
||||
if &lm == &expected {
|
||||
log_print!("{} [应用] {} MD5校验通过 ({}), 继续下一个文件", ts, filename, expected);
|
||||
*ctx_clone.current_download_md5.lock().unwrap() = None;
|
||||
send_next_download(&ctx_clone, &sender);
|
||||
send_next_download(&ctx_clone, &sender, &shutdown_tx_arc_clone);
|
||||
} else {
|
||||
log_print!("{} [应用] {} MD5校验失败 (本地={}, 期望={}),重新下载", ts, filename, lm, expected);
|
||||
// 删除损坏文件,加入队列末尾重新下载
|
||||
@@ -2044,16 +2078,16 @@ async fn run_updater(debug_mode: bool) -> bool {
|
||||
queue.push_back((app_name.to_string(), filename.to_string(), 0, expected));
|
||||
*ctx_clone.current_download_md5.lock().unwrap() = None;
|
||||
drop(queue);
|
||||
send_next_download(&ctx_clone, &sender);
|
||||
send_next_download(&ctx_clone, &sender, &shutdown_tx_arc_clone);
|
||||
}
|
||||
} else {
|
||||
log_print!("{} [应用] {} 无法计算MD5,继续下一个文件", ts, filename);
|
||||
*ctx_clone.current_download_md5.lock().unwrap() = None;
|
||||
send_next_download(&ctx_clone, &sender);
|
||||
send_next_download(&ctx_clone, &sender, &shutdown_tx_arc_clone);
|
||||
}
|
||||
} else {
|
||||
// 没有期望MD5(理论上不应发生),直接继续
|
||||
send_next_download(&ctx_clone, &sender);
|
||||
send_next_download(&ctx_clone, &sender, &shutdown_tx_arc_clone);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -2242,10 +2276,9 @@ async fn main() {
|
||||
(minutes * 60.0) as u64
|
||||
};
|
||||
|
||||
if config.debug_mode {
|
||||
let wait_mins = wait_seconds as f64 / 60.0;
|
||||
println!("Updater 本次检查完成,无更新,等待 {:.1} 分钟后再次检查...", wait_mins);
|
||||
}
|
||||
// 打印等待信息(log_print! 会同时写入控制台和日志文件)
|
||||
let wait_mins = wait_seconds as f64 / 60.0;
|
||||
log_print!("Updater 本次检查完成,无更新,等待 {:.1} 分钟后再次检查...", wait_mins);
|
||||
|
||||
// 分段等待(每 30 秒为一个周期),期间可响应管道消息
|
||||
let mut remaining = wait_seconds;
|
||||
|
||||
Reference in New Issue
Block a user