mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-07-24 17:20:51 +02:00
feat(upload): Add transfer_speed for downloading and uploading files (#1797)
Co-authored-by: Victor Aremu <me@victorare.mu> Co-authored-by: Fabian-Lars <github@fabianlars.de>
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"upload": "minor"
|
||||||
|
"upload-js": "minor"
|
||||||
|
---
|
||||||
|
|
||||||
|
Added feature for calculating `transfer_speed` during file uploads and downloads
|
||||||
@@ -7,6 +7,7 @@ import { invoke, Channel } from '@tauri-apps/api/core'
|
|||||||
interface ProgressPayload {
|
interface ProgressPayload {
|
||||||
progress: number
|
progress: number
|
||||||
total: number
|
total: number
|
||||||
|
transferSpeed: number
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProgressHandler = (progress: ProgressPayload) => void
|
type ProgressHandler = (progress: ProgressPayload) => void
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
|
html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
mod transfer_stats;
|
||||||
|
use transfer_stats::TransferStats;
|
||||||
|
|
||||||
use futures_util::TryStreamExt;
|
use futures_util::TryStreamExt;
|
||||||
use serde::{ser::Serializer, Serialize};
|
use serde::{ser::Serializer, Serialize};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
@@ -55,9 +58,11 @@ impl Serialize for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize)]
|
#[derive(Clone, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
struct ProgressPayload {
|
struct ProgressPayload {
|
||||||
progress: u64,
|
progress: u64,
|
||||||
total: u64,
|
total: u64,
|
||||||
|
transfer_speed: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
@@ -88,11 +93,14 @@ async fn download(
|
|||||||
let mut file = BufWriter::new(File::create(file_path).await?);
|
let mut file = BufWriter::new(File::create(file_path).await?);
|
||||||
let mut stream = response.bytes_stream();
|
let mut stream = response.bytes_stream();
|
||||||
|
|
||||||
|
let mut stats = TransferStats::default();
|
||||||
while let Some(chunk) = stream.try_next().await? {
|
while let Some(chunk) = stream.try_next().await? {
|
||||||
file.write_all(&chunk).await?;
|
file.write_all(&chunk).await?;
|
||||||
|
stats.record_chunk_transfer(chunk.len());
|
||||||
let _ = on_progress.send(ProgressPayload {
|
let _ = on_progress.send(ProgressPayload {
|
||||||
progress: chunk.len() as u64,
|
progress: chunk.len() as u64,
|
||||||
total,
|
total,
|
||||||
|
transfer_speed: stats.transfer_speed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
file.flush().await?;
|
file.flush().await?;
|
||||||
@@ -138,10 +146,16 @@ async fn upload(
|
|||||||
fn file_to_body(channel: Channel<ProgressPayload>, file: File) -> reqwest::Body {
|
fn file_to_body(channel: Channel<ProgressPayload>, file: File) -> reqwest::Body {
|
||||||
let stream = FramedRead::new(file, BytesCodec::new()).map_ok(|r| r.freeze());
|
let stream = FramedRead::new(file, BytesCodec::new()).map_ok(|r| r.freeze());
|
||||||
|
|
||||||
|
let mut stats = TransferStats::default();
|
||||||
reqwest::Body::wrap_stream(ReadProgressStream::new(
|
reqwest::Body::wrap_stream(ReadProgressStream::new(
|
||||||
stream,
|
stream,
|
||||||
Box::new(move |progress, total| {
|
Box::new(move |progress, total| {
|
||||||
let _ = channel.send(ProgressPayload { progress, total });
|
stats.record_chunk_transfer(progress as usize);
|
||||||
|
let _ = channel.send(ProgressPayload {
|
||||||
|
progress,
|
||||||
|
total,
|
||||||
|
transfer_speed: stats.transfer_speed,
|
||||||
|
});
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
// The TransferStats struct is used to track and calculate the transfer speed of data chunks over time.
|
||||||
|
pub struct TransferStats {
|
||||||
|
accumulated_chunk_len: usize, // Total length of chunks transferred in the current period
|
||||||
|
accumulated_time: u128, // Total time taken for the transfers in the current period
|
||||||
|
pub transfer_speed: u64, // Calculated transfer speed in bytes per second
|
||||||
|
start_time: Instant, // Time when the current period started
|
||||||
|
granularity: u32, // Time period (in milliseconds) over which the transfer speed is calculated
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransferStats {
|
||||||
|
// Initializes a new TransferStats instance with the specified granularity.
|
||||||
|
pub fn start(granularity: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
accumulated_chunk_len: 0,
|
||||||
|
accumulated_time: 0,
|
||||||
|
transfer_speed: 0,
|
||||||
|
start_time: Instant::now(),
|
||||||
|
granularity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Records the transfer of a data chunk and updates the transfer speed if the granularity period has elapsed.
|
||||||
|
pub fn record_chunk_transfer(&mut self, chunk_len: usize) {
|
||||||
|
let now = Instant::now();
|
||||||
|
let it_took = now.duration_since(self.start_time).as_millis();
|
||||||
|
self.accumulated_chunk_len += chunk_len;
|
||||||
|
self.accumulated_time += it_took;
|
||||||
|
|
||||||
|
// If the accumulated time exceeds the granularity, calculate the transfer speed.
|
||||||
|
if self.accumulated_time >= self.granularity as u128 {
|
||||||
|
self.transfer_speed =
|
||||||
|
(self.accumulated_chunk_len as u128 / self.accumulated_time * 1024) as u64;
|
||||||
|
self.accumulated_chunk_len = 0;
|
||||||
|
self.accumulated_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the start time for the next period.
|
||||||
|
self.start_time = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provides a default implementation for TransferStats with a granularity of 500 milliseconds.
|
||||||
|
impl Default for TransferStats {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::start(500) // Default granularity is 500
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user