From 7fbeac991b21bf5fe6d9ed4596c610387c831d56 Mon Sep 17 00:00:00 2001 From: zqm Date: Fri, 10 Apr 2026 14:49:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Windows/CS/Framework4.0/Updater/src/main.rs | 71 +++++++++++++++------ 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/Windows/CS/Framework4.0/Updater/src/main.rs b/Windows/CS/Framework4.0/Updater/src/main.rs index 6de0bbc..b5f7f09 100644 --- a/Windows/CS/Framework4.0/Updater/src/main.rs +++ b/Windows/CS/Framework4.0/Updater/src/main.rs @@ -809,7 +809,12 @@ fn request_download_for_app( /// 从待下载队列取出一个文件发送(顺序下载) -fn send_next_download(ctx: &Arc, sender: &cube_lib::websocket::MessageSender) { +/// shutdown_tx: 进入 Complete 阶段后发送此信号断开连接 +fn send_next_download( + ctx: &Arc, + sender: &cube_lib::websocket::MessageSender, + shutdown_tx: &std::sync::Arc>>> +) { 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, 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> = 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;