diff --git a/desktop/app.vue b/desktop/app.vue index fb5f882e..f81c4321 100644 --- a/desktop/app.vue +++ b/desktop/app.vue @@ -6,7 +6,7 @@ diff --git a/desktop/src-tauri/src/downloads/download_manager.rs b/desktop/src-tauri/src/downloads/download_manager.rs index 86c006a0..f6604303 100644 --- a/desktop/src-tauri/src/downloads/download_manager.rs +++ b/desktop/src-tauri/src/downloads/download_manager.rs @@ -41,7 +41,8 @@ pub enum DownloadManagerSignal { /// Any error which occurs in the agent Error(GameDownloadError), /// Pushes UI update - Update, + UpdateUIQueue, + UpdateUIStats(usize, usize), //kb/s and seconds /// Uninstall game /// Takes game ID Uninstall(String), @@ -156,7 +157,7 @@ impl DownloadManager { let to_move = queue.remove(current_index).unwrap(); queue.insert(new_index, to_move); self.command_sender - .send(DownloadManagerSignal::Update) + .send(DownloadManagerSignal::UpdateUIQueue) .unwrap(); } pub fn cancel(&self, game_id: String) { @@ -188,7 +189,7 @@ impl DownloadManager { self.command_sender.send(DownloadManagerSignal::Go).unwrap(); } self.command_sender - .send(DownloadManagerSignal::Update) + .send(DownloadManagerSignal::UpdateUIQueue) .unwrap(); } pub fn pause_downloads(&self) { diff --git a/desktop/src-tauri/src/downloads/download_manager_builder.rs b/desktop/src-tauri/src/downloads/download_manager_builder.rs index 6719b3fe..3d813fdc 100644 --- a/desktop/src-tauri/src/downloads/download_manager_builder.rs +++ b/desktop/src-tauri/src/downloads/download_manager_builder.rs @@ -16,7 +16,7 @@ use crate::{ db::{Database, GameStatus, GameTransientStatus}, library::{ on_game_complete, push_game_update, GameUpdateEvent, QueueUpdateEvent, - QueueUpdateEventQueueData, + QueueUpdateEventQueueData, StatsUpdateEvent, }, state::{GameStatusManager, GameStatusWithTransient}, DB, @@ -128,7 +128,13 @@ impl DownloadManagerBuilder { push_game_update(&self.app_handle, id, status); } - fn push_manager_update(&self) { + fn push_ui_stats_update(&self, kbs: usize, time: usize) { + let event_data = StatsUpdateEvent { speed: kbs, time }; + + self.app_handle.emit("update_stats", event_data).unwrap(); + } + + fn push_ui_queue_update(&self) { let queue = self.download_queue.read(); let queue_objs: Vec = queue .iter() @@ -208,8 +214,11 @@ impl DownloadManagerBuilder { DownloadManagerSignal::Cancel => { self.manage_cancel_signal(); } - DownloadManagerSignal::Update => { - self.push_manager_update(); + DownloadManagerSignal::UpdateUIQueue => { + self.push_ui_queue_update(); + } + DownloadManagerSignal::UpdateUIStats(kbs, time) => { + self.push_ui_stats_update(kbs, time); } DownloadManagerSignal::Finish => { self.stop_and_wait_current_download(); @@ -315,7 +324,7 @@ impl DownloadManagerBuilder { self.manage_go_signal(); } - self.push_manager_update(); + self.push_ui_queue_update(); } fn manage_stop_signal(&mut self) { @@ -356,7 +365,9 @@ impl DownloadManagerBuilder { } } } - self.sender.send(DownloadManagerSignal::Update).unwrap(); + self.sender + .send(DownloadManagerSignal::UpdateUIQueue) + .unwrap(); self.sender.send(DownloadManagerSignal::Go).unwrap(); } @@ -406,7 +417,9 @@ impl DownloadManagerBuilder { GameTransientStatus::Downloading { version_name }, ); }); - self.sender.send(DownloadManagerSignal::Update).unwrap(); + self.sender + .send(DownloadManagerSignal::UpdateUIQueue) + .unwrap(); } fn manage_go_signal(&mut self) { @@ -483,7 +496,9 @@ impl DownloadManagerBuilder { ); }); - self.sender.send(DownloadManagerSignal::Update).unwrap(); + self.sender + .send(DownloadManagerSignal::UpdateUIQueue) + .unwrap(); } fn manage_error_signal(&mut self, error: GameDownloadError) { let current_status = self.current_download_agent.clone().unwrap(); @@ -504,7 +519,9 @@ impl DownloadManagerBuilder { db_handle.games.transient_statuses.remove(id); }); - self.sender.send(DownloadManagerSignal::Update).unwrap(); + self.sender + .send(DownloadManagerSignal::UpdateUIQueue) + .unwrap(); } fn manage_cancel_signal(&mut self) { self.stop_and_wait_current_download(); diff --git a/desktop/src-tauri/src/downloads/progress_object.rs b/desktop/src-tauri/src/downloads/progress_object.rs index 22077027..2e0a1943 100644 --- a/desktop/src-tauri/src/downloads/progress_object.rs +++ b/desktop/src-tauri/src/downloads/progress_object.rs @@ -2,9 +2,9 @@ use std::{ sync::{ atomic::{AtomicUsize, Ordering}, mpsc::Sender, - Arc, Mutex, + Arc, Mutex, RwLock, }, - time::Instant, + time::{Duration, Instant}, }; use log::info; @@ -20,6 +20,8 @@ pub struct ProgressObject { points_towards_update: Arc, points_to_push_update: Arc, + last_update: Arc>, + amount_last_update: Arc, } pub struct ProgressHandle { @@ -59,6 +61,8 @@ 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)), } } @@ -69,12 +73,42 @@ impl ProgressObject { let to_update = self.points_to_push_update.fetch_add(0, Ordering::Relaxed); - if current_amount < to_update { - return; + if current_amount >= to_update { + self.points_towards_update + .fetch_sub(to_update, Ordering::Relaxed); + self.sender + .send(DownloadManagerSignal::UpdateUIQueue) + .unwrap(); + } + + 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); + self.sender + .send(DownloadManagerSignal::UpdateUIStats( + kilobytes_per_second, + time_remaining, + )) + .unwrap(); } - self.points_towards_update - .fetch_sub(to_update, Ordering::Relaxed); - self.sender.send(DownloadManagerSignal::Update).unwrap(); } pub fn set_time_now(&self) { diff --git a/desktop/src-tauri/src/library.rs b/desktop/src-tauri/src/library.rs index a4c6e442..01b63f91 100644 --- a/desktop/src-tauri/src/library.rs +++ b/desktop/src-tauri/src/library.rs @@ -53,6 +53,12 @@ pub struct QueueUpdateEvent { pub status: DownloadManagerStatus, } +#[derive(serde::Serialize, Clone)] +pub struct StatsUpdateEvent { + pub speed: usize, + pub time: usize, +} + // Game version with some fields missing and size information #[derive(serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 539954ce..2c770d17 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -3935,11 +3935,6 @@ mlly@^1.3.0, mlly@^1.4.2, mlly@^1.6.1, mlly@^1.7.1: pkg-types "^1.2.0" ufo "^1.5.4" -moment@^2.30.1: - version "2.30.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" - integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== - mri@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"