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


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) }
}

文章作者: Yang · Mr
版權聲明: 本部落格所有文章除特別聲明外,均採用 CC BY 4.0 許可協議。轉載請註明來源 Yang · Mr !
评论
  目錄