tauri-apps / plugins-workspace

All of the official Tauri plugins in one place!
https://tauri.app
Apache License 2.0
930 stars 260 forks source link

[bug][Upload][v2] The callback function progressHandler in the upload method sometimes works, sometimes it doesn't. #1490

Open DWHengr opened 4 months ago

DWHengr commented 4 months ago

The callback function progressHandler in the upload method sometimes works, sometimes it doesn't. The download method is not a problem. The progressHandler function in the upload method does not trigger after being triggered a few times.

My file is around 30 megabytes, and the progressHandler triggered these a few times: image

DWHengr commented 4 months ago

[✔] Environment

[-] Packages

[-] App

FabianLars commented 4 months ago

Would you happen to be able to provide a minimal reproduction example? It seems to work fine on my end so it may be implementation specific (doesn't rule out a bug in the plugin)

DWHengr commented 4 months ago

@FabianLars I found that the backend has fully received the files from the frontend and the request is complete. But the front-end progress has only been printed a few times. This number of times is uncertain, depending on when the request is completed. Moreover, this issue is particularly evident when uploading the same file here for the second time. Here is an example: https://github.com/DWHengr/upload-demo

FabianLars commented 4 months ago

Actually now that i think about it, i talked to someone on Discord about a similar problem where the ipc::Channel kept losing events just like this. I can't find the convos anymore thore, but maybe @lucasfernog remembers something (i know that i pinged you for it but idk what happened after lol)

DWHengr commented 3 months ago

Is there any solution. I am unable to display the progress of file upload correctly at the moment.

kingyang commented 1 month ago

I've encountered the same issue. Could it be caused by the high frequency of these messages? I'm not sure if adding a debounce might solve the problem.

kingyang commented 1 month ago
#[command]
async fn download(
    url: &str,
    file_path: &str,
    headers: HashMap<String, String>,
    on_progress: Channel<ProgressPayload>,
) -> Result<()> {
    let client = reqwest::Client::new();

    let mut request = client.get(url);
    // Loop trought the headers keys and values
    // and add them to the request object.
    for (key, value) in headers {
        request = request.header(&key, value);
    }

    let response = request.send().await?;
    let total = response.content_length().unwrap_or(0);

    let mut file = BufWriter::new(File::create(file_path).await?);
    let mut stream = response.bytes_stream();

    let mut last_progress = 0u64;
    let mut last_send_time = Instant::now();
    let debounce_duration = std::time::Duration::from_millis(200);

    while let Some(chunk) = stream.try_next().await? {
        file.write_all(&chunk).await?;
        last_progress = last_progress + chunk.len() as u64;
        if last_send_time.elapsed() >= debounce_duration || last_progress == total {
            let _ = on_progress.send(ProgressPayload {
                progress: last_progress,
                total,
            });
            last_send_time = Instant::now();
        }
    }
    file.flush().await?;

    Ok(())
}

You can try this code

BaLaLaLs commented 1 week ago
#[command]
async fn download(
    url: &str,
    file_path: &str,
    headers: HashMap<String, String>,
    on_progress: Channel<ProgressPayload>,
) -> Result<()> {
    let client = reqwest::Client::new();

    let mut request = client.get(url);
    // Loop trought the headers keys and values
    // and add them to the request object.
    for (key, value) in headers {
        request = request.header(&key, value);
    }

    let response = request.send().await?;
    let total = response.content_length().unwrap_or(0);

    let mut file = BufWriter::new(File::create(file_path).await?);
    let mut stream = response.bytes_stream();

    let mut last_progress = 0u64;
    let mut last_send_time = Instant::now();
    let debounce_duration = std::time::Duration::from_millis(200);

    while let Some(chunk) = stream.try_next().await? {
        file.write_all(&chunk).await?;
        last_progress = last_progress + chunk.len() as u64;
        if last_send_time.elapsed() >= debounce_duration || last_progress == total {
            let _ = on_progress.send(ProgressPayload {
                progress: last_progress,
                total,
            });
            last_send_time = Instant::now();
        }
    }
    file.flush().await?;

    Ok(())
}

你可以尝试这个代码 I think this code is what people expected. Have you considered modifying it into the upload plugin

kingyang commented 5 days ago

@BaLaLaLs Thank you for your reply. I'm not an expert in Rust and Tauri, so I'm not sure if this is a better solution (I personally think it might be an issue with Tauri 2.0's messaging mechanism, as high-frequency messages could cause message deadlocks, but other APIs' transformCallback work normally, meaning I haven't yet identified the essence of the problem). Additionally, this code was modified based on suggestions from GPT, so I recommend using it as a reference for now.