- 新增 handleExternalLink 方法处理链接点击事件 - 更新 success 页面样式,增强视觉效果 - 添加 MiSans 字体支持 - 引入最新资源列表展示功能 - 优化按钮交互效果和页面布局
148 lines
4.4 KiB
Rust
148 lines
4.4 KiB
Rust
|
||
// --- 1. 导入所需模块 ---
|
||
use thiserror::Error;
|
||
use zip::ZipArchive;
|
||
use std::fs::{self, File};
|
||
use std::io;
|
||
use std::path::PathBuf;
|
||
use serde::Serialize;
|
||
use tauri::Emitter;
|
||
|
||
|
||
// --- 2. (新增) 定义事件的有效负载 (Payload) ---
|
||
// 这个结构体将作为事件发送给 Svelte
|
||
#[derive(Clone, serde::Serialize)]
|
||
struct InstallProgress {
|
||
message: String,
|
||
percentage: f32, // 0.0 到 100.0
|
||
}
|
||
|
||
// --- 3. 错误定义 ---
|
||
#[derive(Debug, Error)]
|
||
pub enum InstallError {
|
||
#[error("IO 错误: {0}")]
|
||
Io(#[from] std::io::Error),
|
||
|
||
#[error("Zip 解压错误: {0}")]
|
||
Zip(#[from] zip::result::ZipError),
|
||
|
||
#[error("找不到 data.bin 文件: {0}")]
|
||
DataFileNotFound(String),
|
||
|
||
|
||
}
|
||
|
||
|
||
impl Serialize for InstallError {
|
||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||
where
|
||
S: serde::Serializer,
|
||
{
|
||
serializer.serialize_str(self.to_string().as_ref())
|
||
}
|
||
}
|
||
|
||
|
||
#[tauri::command]
|
||
// --- 5. (修改) 添加 window 参数 ---
|
||
pub async fn install_game(window: tauri::Window, target_dir: String) -> Result<String, InstallError> {
|
||
|
||
println!("Rust 后端收到命令:目标目录 {}", target_dir);
|
||
|
||
// --- 6. 核心改动:从文件系统读取 data.bin ---
|
||
|
||
// --- 6a. (新增) 发送启动事件 ---
|
||
window.emit("install_progress", InstallProgress {
|
||
message: "安装开始...".into(),
|
||
percentage: 0.0
|
||
}).ok();
|
||
|
||
// 1. 获取 app.exe 所在的目录
|
||
let exe_path = std::env::current_exe()?;
|
||
let exe_dir = exe_path.parent()
|
||
.ok_or_else(|| InstallError::Io(io::Error::new(io::ErrorKind::NotFound, "无法获取执行文件所在目录")))?;
|
||
|
||
// 2. 构造 data.bin 的路径
|
||
let data_bin_path = exe_dir.join("data.bin");
|
||
|
||
println!("正在获取游戏资源包: {:?}", data_bin_path);
|
||
window.emit("install_progress", InstallProgress {
|
||
message: "正在获取游戏资源包".into(),
|
||
percentage: 1.0 // 1%
|
||
}).ok();
|
||
|
||
|
||
if !data_bin_path.exists() {
|
||
// 返回错误,Svelte 的 catch 块会捕获它
|
||
return Err(InstallError::DataFileNotFound(
|
||
format!("未在 {:?} 找到游戏资源包,请重新下载", data_bin_path)
|
||
));
|
||
}
|
||
|
||
// 3. 从硬盘打开文件
|
||
let archive_file = File::open(&data_bin_path)?;
|
||
println!("成功打开游戏资源包");
|
||
window.emit("install_progress", InstallProgress {
|
||
message: "成功打开游戏资源包".into(),
|
||
percentage: 5.0 // 5%
|
||
}).ok();
|
||
|
||
|
||
// 4. ZipArchive 现在读取文件
|
||
let mut archive = ZipArchive::new(archive_file)?;
|
||
|
||
let total_files = archive.len() as f32;
|
||
println!("在游戏资源包中找到 {} 个文件。", total_files);
|
||
window.emit("install_progress", InstallProgress {
|
||
message: format!("包中找到 {} 个文件。", total_files),
|
||
percentage: 10.0 // 10%
|
||
}).ok();
|
||
|
||
|
||
// --- 7. 解压循环 (核心改动: 添加 emit) ---
|
||
let install_path = PathBuf::from(target_dir);
|
||
fs::create_dir_all(&install_path)?;
|
||
|
||
for i in 0..archive.len() {
|
||
let mut file = archive.by_index(i)?;
|
||
|
||
let outpath = match file.enclosed_name() {
|
||
Some(path) => install_path.join(path),
|
||
None => continue,
|
||
};
|
||
|
||
// --- 7a. (核心) 计算百分比并发送事件 ---
|
||
let current_file_index = i as f32;
|
||
let percentage = 10.0 + (current_file_index / total_files) * 85.0; // (10% + 85% = 95%)
|
||
let message = format!("安装中 [{}/{}]: {}", i + 1, total_files as u32, file.name());
|
||
|
||
window.emit("install_progress", InstallProgress { message, percentage })
|
||
.ok();
|
||
|
||
// --- 2. (新增) 关键修复 ---
|
||
// 释放线程 1 毫秒,给 Svelte 留出渲染时间
|
||
// sleep(Duration::from_millis(1)).await;
|
||
|
||
if (&*file.name()).ends_with('/') {
|
||
fs::create_dir_all(&outpath)?;
|
||
} else {
|
||
if let Some(p) = outpath.parent() {
|
||
if !p.exists() {
|
||
fs::create_dir_all(p)?;
|
||
}
|
||
}
|
||
let mut outfile = File::create(&outpath)?;
|
||
io::copy(&mut file, &mut outfile)?;
|
||
}
|
||
} // --- 循环结束 ---
|
||
|
||
println!("Rust 后端:解压成功。");
|
||
window.emit("install_progress", InstallProgress {
|
||
message: "安装成功".into(),
|
||
percentage: 100.0 // 100%
|
||
}).ok();
|
||
|
||
Ok(format!("成功解压 {} 个文件到指定目录!", total_files as u32))
|
||
}
|
||
|