Skip to content

Commit

Permalink
feat(upload): Add transfer_speed for downloading and uploading files (#…
Browse files Browse the repository at this point in the history
…1797)

Co-authored-by: Victor Aremu <[email protected]>
Co-authored-by: Fabian-Lars <[email protected]>
  • Loading branch information
3 people authored Nov 4, 2024
1 parent e0d2e2c commit 87cc585
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
6 changes: 6 additions & 0 deletions .changes/add-transfer-speed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"upload": "minor"
"upload-js": "minor"
---

Added feature for calculating `transfer_speed` during file uploads and downloads
1 change: 1 addition & 0 deletions plugins/upload/guest-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { invoke, Channel } from '@tauri-apps/api/core'
interface ProgressPayload {
progress: number
total: number
transferSpeed: number
}

type ProgressHandler = (progress: ProgressPayload) => void
Expand Down
16 changes: 15 additions & 1 deletion plugins/upload/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
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 serde::{ser::Serializer, Serialize};
use tauri::{
Expand Down Expand Up @@ -55,9 +58,11 @@ impl Serialize for Error {
}

#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
struct ProgressPayload {
progress: u64,
total: u64,
transfer_speed: u64,
}

#[command]
Expand Down Expand Up @@ -88,11 +93,14 @@ async fn download(
let mut file = BufWriter::new(File::create(file_path).await?);
let mut stream = response.bytes_stream();

let mut stats = TransferStats::default();
while let Some(chunk) = stream.try_next().await? {
file.write_all(&chunk).await?;
stats.record_chunk_transfer(chunk.len());
let _ = on_progress.send(ProgressPayload {
progress: chunk.len() as u64,
total,
transfer_speed: stats.transfer_speed,
});
}
file.flush().await?;
Expand Down Expand Up @@ -138,10 +146,16 @@ async fn upload(
fn file_to_body(channel: Channel<ProgressPayload>, file: File) -> reqwest::Body {
let stream = FramedRead::new(file, BytesCodec::new()).map_ok(|r| r.freeze());

let mut stats = TransferStats::default();
reqwest::Body::wrap_stream(ReadProgressStream::new(
stream,
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,
});
}),
))
}
Expand Down
52 changes: 52 additions & 0 deletions plugins/upload/src/transfer_stats.rs
Original file line number Diff line number Diff line change
@@ -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
}
}

0 comments on commit 87cc585

Please sign in to comment.