From b692a1d8310f089ca53bb1adc65169c5542742ed Mon Sep 17 00:00:00 2001 From: quexeky <116044207+quexeky@users.noreply.github.com> Date: Sun, 19 Jan 2025 08:41:20 +1100 Subject: [PATCH] chore: Progress on rolling progress window --- desktop/src-tauri/Cargo.lock | 7 ++ desktop/src-tauri/Cargo.toml | 1 + desktop/src-tauri/src/cleanup.rs | 9 +- .../src/download_manager/progress_object.rs | 87 +++++++++---------- .../rolling_progress_updates.rs | 8 +- desktop/src-tauri/src/lib.rs | 5 +- desktop/src-tauri/src/remote/auth.rs | 12 ++- desktop/src-tauri/src/remote/commands.rs | 5 +- 8 files changed, 74 insertions(+), 60 deletions(-) diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 0c8123bf..c7307bf8 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -255,6 +255,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "atomic-instant-full" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6541700e074cda41b1c6f98c2cae6cde819967bf142078f069cad85387cdbe" + [[package]] name = "atomic-waker" version = "1.1.2" @@ -1033,6 +1039,7 @@ dependencies = [ name = "drop-app" version = "0.1.0" dependencies = [ + "atomic-instant-full", "boxcar", "chrono", "derive_builder", diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index c48f4904..31a23af1 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -52,6 +52,7 @@ throttle_my_fn = "0.2.6" parking_lot = "0.12.3" merge-struct = "0.1.0" serde_merge = "0.1.3" +atomic-instant-full = "0.1.0" [dependencies.tauri] version = "2.1.1" diff --git a/desktop/src-tauri/src/cleanup.rs b/desktop/src-tauri/src/cleanup.rs index 64f0bde0..b45fb063 100644 --- a/desktop/src-tauri/src/cleanup.rs +++ b/desktop/src-tauri/src/cleanup.rs @@ -1,4 +1,4 @@ -use log::{debug, info}; +use log::{debug, error}; use tauri::AppHandle; use crate::AppState; @@ -12,7 +12,12 @@ pub fn cleanup_and_exit(app: &AppHandle, state: &tauri::State<'_, std::sync::Mut debug!("Cleaning up and exiting application"); let download_manager = state.lock().unwrap().download_manager.clone(); match download_manager.ensure_terminated() { - Ok(_) => {}, + Ok(res) => { + match res { + Ok(_) => debug!("Download manager terminated correctly"), + Err(_) => error!("Download manager failed to terminate correctly"), + } + }, Err(e) => panic!("{:?}", e), } diff --git a/desktop/src-tauri/src/download_manager/progress_object.rs b/desktop/src-tauri/src/download_manager/progress_object.rs index 262269bd..246d8437 100644 --- a/desktop/src-tauri/src/download_manager/progress_object.rs +++ b/desktop/src-tauri/src/download_manager/progress_object.rs @@ -7,10 +7,11 @@ use std::{ time::{Duration, Instant}, }; +use atomic_instant_full::AtomicInstant; use log::info; use throttle_my_fn::throttle; -use super::download_manager::DownloadManagerSignal; +use super::{download_manager::DownloadManagerSignal, rolling_progress_updates::RollingProgressWindow}; #[derive(Clone)] pub struct ProgressObject { @@ -20,8 +21,10 @@ pub struct ProgressObject { sender: Sender, points_towards_update: Arc, points_to_push_update: Arc, - last_update: Arc>, - amount_last_update: Arc, + //last_update: Arc>, + last_update_time: Arc, + bytes_last_update: Arc, + rolling: RollingProgressWindow<128> } pub struct ProgressHandle { @@ -42,7 +45,7 @@ impl ProgressHandle { pub fn add(&self, amount: usize) { self.progress .fetch_add(amount, std::sync::atomic::Ordering::Relaxed); - self.progress_object.check_push_update(amount); + push_update(&self.progress_object, amount); } } @@ -61,50 +64,13 @@ impl ProgressObject { points_towards_update: Arc::new(AtomicUsize::new(0)), points_to_push_update: Arc::new(AtomicUsize::new(points_to_push_update)), - last_update: Arc::new(RwLock::new(Instant::now())), - amount_last_update: Arc::new(AtomicUsize::new(0)), + last_update_time: Arc::new(AtomicInstant::now()), + bytes_last_update: Arc::new(AtomicUsize::new(0)), + rolling: RollingProgressWindow::new(), } } - pub fn check_push_update(&self, amount_added: usize) { - let current_amount = self - .points_towards_update - .fetch_add(amount_added, Ordering::Relaxed); - - let to_update = self.points_to_push_update.fetch_add(0, Ordering::Relaxed); - - if current_amount >= to_update { - self.points_towards_update - .fetch_sub(to_update, Ordering::Relaxed); - update_queue(self); - } - - let last_update = self.last_update.read().unwrap(); - let last_update_difference = Instant::now().duration_since(*last_update).as_millis(); - if last_update_difference > 1000 { - // push update - drop(last_update); - let mut last_update = self.last_update.write().unwrap(); - *last_update = Instant::now(); - drop(last_update); - - let current_amount = self.sum(); - let max = self.get_max(); - let amount_at_last_update = self.amount_last_update.fetch_add(0, Ordering::Relaxed); - self.amount_last_update - .store(current_amount, Ordering::Relaxed); - - let amount_since_last_update = current_amount - amount_at_last_update; - - let kilobytes_per_second = - amount_since_last_update / (last_update_difference as usize).max(1); - - let remaining = max - current_amount; // bytes - let time_remaining = (remaining / 1000) / kilobytes_per_second.max(1); - - update_ui(self, kilobytes_per_second, time_remaining); - } - } + pub fn set_time_now(&self) { *self.start.lock().unwrap() = Instant::now(); @@ -136,23 +102,48 @@ impl ProgressObject { pub fn get(&self, index: usize) -> Arc { self.progress_instances.lock().unwrap()[index].clone() } + fn update_window(&self, kilobytes_per_second: usize) { + self.rolling.update(kilobytes_per_second); + } } -#[throttle(50, Duration::from_secs(1))] +#[throttle(1, Duration::from_millis(100))] fn update_ui(progress_object: &ProgressObject, kilobytes_per_second: usize, time_remaining: usize) { progress_object .sender .send(DownloadManagerSignal::UpdateUIStats( - kilobytes_per_second, + progress_object.rolling.get_average(), time_remaining, )) .unwrap(); } -#[throttle(50, Duration::from_secs(1))] +#[throttle(1, Duration::from_millis(100))] fn update_queue(progress: &ProgressObject) { progress .sender .send(DownloadManagerSignal::UpdateUIQueue) .unwrap(); } + +#[throttle(1, Duration::from_millis(20))] +pub fn push_update(progress: &ProgressObject, amount_added: usize) { + let last_update_time = progress.last_update_time.swap(Instant::now(), Ordering::SeqCst); + let time_since_last_update = Instant::now().duration_since(last_update_time).as_millis(); + + let current_bytes_downloaded = progress.sum(); + let max = progress.get_max(); + let bytes_at_last_update = progress.bytes_last_update.swap(current_bytes_downloaded, Ordering::Relaxed); + + let bytes_since_last_update = current_bytes_downloaded - bytes_at_last_update; + + let kilobytes_per_second = + bytes_since_last_update / (time_since_last_update as usize).max(1); + + let bytes_remaining = max - current_bytes_downloaded; // bytes + let time_remaining = (bytes_remaining / 1000) / kilobytes_per_second.max(1); + + progress.update_window(kilobytes_per_second); + + update_ui(progress, kilobytes_per_second, time_remaining); +} \ No newline at end of file diff --git a/desktop/src-tauri/src/download_manager/rolling_progress_updates.rs b/desktop/src-tauri/src/download_manager/rolling_progress_updates.rs index 99e87738..bb7a5081 100644 --- a/desktop/src-tauri/src/download_manager/rolling_progress_updates.rs +++ b/desktop/src-tauri/src/download_manager/rolling_progress_updates.rs @@ -9,12 +9,18 @@ pub struct RollingProgressWindow { current: Arc, } impl RollingProgressWindow { + pub fn new() -> Self { + Self { + window: Arc::new([(); S].map(|_| AtomicUsize::new(0))), + current: Arc::new(AtomicUsize::new(0)) + } + } pub fn update(&self, kilobytes_per_second: usize) { let index = self.current.fetch_add(1, Ordering::SeqCst); let current = &self.window[index % S]; current.store(kilobytes_per_second, Ordering::Release); } pub fn get_average(&self) -> usize { - self.window.iter().map(|x| x.load(Ordering::Relaxed)).sum() + self.window.iter().map(|x| x.load(Ordering::Relaxed)).sum::() / S } } diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index e5a1bf9a..356a4da4 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -45,6 +45,7 @@ use remote::commands::{ auth_initiate, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote, }; use serde::{Deserialize, Serialize}; +use tauri::ipc::IpcResponse; use std::path::Path; use std::sync::Arc; use std::{ @@ -136,7 +137,7 @@ fn setup(handle: AppHandle) -> AppState<'static> { debug!("Database is set up"); // TODO: Account for possible failure - let (app_status, user) = auth::setup().unwrap(); + let (app_status, user) = auth::setup(); let db_handle = DB.borrow_data().unwrap(); let mut missing_games = Vec::new(); @@ -315,7 +316,7 @@ pub fn run() { app.webview_windows().get("main").unwrap().show().unwrap(); } "quit" => { - cleanup_and_exit(app, &state); + cleanup_and_exit(app, &app.state()); } _ => { diff --git a/desktop/src-tauri/src/remote/auth.rs b/desktop/src-tauri/src/remote/auth.rs index afd0c9a9..ba2c6631 100644 --- a/desktop/src-tauri/src/remote/auth.rs +++ b/desktop/src-tauri/src/remote/auth.rs @@ -180,15 +180,19 @@ pub fn auth_initiate_logic() -> Result<(), RemoteAccessError> { Ok(()) } -pub fn setup() -> Result<(AppStatus, Option), RemoteAccessError> { +pub fn setup() -> (AppStatus, Option) { let data = DB.borrow_data().unwrap(); let auth = data.auth.clone(); drop(data); if auth.is_some() { - let user_result = fetch_user()?; - return Ok((AppStatus::SignedIn, Some(user_result))); + let user_result = match fetch_user() { + Ok(data) => data, + Err(RemoteAccessError::FetchError(_)) => return (AppStatus::ServerUnavailable, None), + Err(_) => return (AppStatus::SignedInNeedsReauth, None), + }; + return (AppStatus::SignedIn, Some(user_result)); } - Ok((AppStatus::SignedOut, None)) + (AppStatus::SignedOut, None) } diff --git a/desktop/src-tauri/src/remote/commands.rs b/desktop/src-tauri/src/remote/commands.rs index 9dbfcb46..a2346efb 100644 --- a/desktop/src-tauri/src/remote/commands.rs +++ b/desktop/src-tauri/src/remote/commands.rs @@ -57,14 +57,13 @@ pub fn sign_out(app: AppHandle) { } #[tauri::command] -pub fn retry_connect(state: tauri::State<'_, Mutex>) -> UserValue<(), RemoteAccessError> { - let (app_status, user) = setup()?; +pub fn retry_connect(state: tauri::State<'_, Mutex>) { + let (app_status, user) = setup(); let mut guard = state.lock().unwrap(); guard.status = app_status; guard.user = user; drop(guard); - UserValue::Ok(()) } #[tauri::command]