tauri通过rust流式下载文件,并计算进度返回给前端

我通过Tauri前端中下载文件并展示进度事遇到了一些问题,通过a链接xhr下载总是有webview自带的下载提示,感觉很不友好,这里提供一个解决方案如下:

首先在main.rs 中定义一个全局变量(需要返回前端)

// 全局进度信息
static mut GLOBAL_VARIABLE: String = String::new();
// 下载文件的大小
static mut GLOBAL_TOTAL: f64 = 0.0;
// 是否下载中0否 1是
static mut ISDOWN: u64 = 0;

然后再通过tauri返回给前端这个下载函数

//流式下载文件
#[tauri::command]
async fn download_file_q(url: String, path: String, puse: u64) -> Result<String, String> {
unsafe {
println!("ISDOWN:{}", ISDOWN);
if ISDOWN >= 1 {
return Err("Another file is currently downloading".into());
}
// ISDOWN = 1
}
let client = reqwest::Client::new();

let mut file: File = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
.map_err(|e| e.to_string())?;

let file_len: u64 = file.metadata().map(|m: fs::Metadata| m.len()).unwrap_or(0);

// 记录下总大小防止关闭软件后计算的总大小不对
let response_t = client.get(&url).send().await.map_err(|e| e.to_string())?;
if response_t.status().is_success() {
let total_size_t = response_t.content_length().unwrap_or(0) as f64;
unsafe {
GLOBAL_TOTAL = response_t.content_length().unwrap_or(0) as f64;
}

let response: reqwest::Response = client
.get(&url)
.header("Range", format!("bytes={}-", file_len))
.send()
.await
.map_err(|e: reqwest::Error| e.to_string())?;

if response.status().is_success() {
unsafe {
// 这个total_size不是一定准的 因为写入了range 会从上次下载的位置开始下载 所以用 total_size_t
// let total_size = response.content_length().unwrap_or(0) as f64;
let mut stream = response.bytes_stream();

file.seek(std::io::SeekFrom::End(0))
.map_err(|e| e.to_string())?;

while let Some(chunk) = stream.next().await {
let bytes = chunk.map_err(|e: reqwest::Error| e.to_string())?;

file.write_all(&bytes)
.map_err(|e: io::Error| e.to_string())?;

let file_len: u64 = file.metadata().map(|m: fs::Metadata| m.len()).unwrap_or(0);
let progress: f64 = (file_len as f64 / total_size_t as f64) * 100.0;
GLOBAL_VARIABLE = format!("{:.2}:{}:{}", progress, file_len, total_size_t);
println!(
"Download Progress: {:.2}% ({}/{} bytes)",
progress, file_len, total_size_t
);

if puse > 0 {
// 暂停下载,让出执行权
tokio::task::yield_now().await;
break;
} else {
}

// 下载完成
if file_len as f64 >= total_size_t {
// 重置全局变量和状态
ISDOWN = 0;
GLOBAL_VARIABLE = String::new();
println!("ISDOWN-suceess:{}", ISDOWN);
// 重新打开文件,清除已下载的内容
// file_len_t = 0;
println!("下载完成");
// break;
}
}
}
}

Ok("Download completed".into())
} else {
unsafe {
ISDOWN = 0;
}
Err("Download failed, response status is not success:1001".into())
}
}

然后通过一个函数获取下载进度信息

// 获取下载文件的信息
#[tauri::command]
fn glob() -> String {
unsafe { format!("{}", GLOBAL_VARIABLE) }
}