From 63c3cc109601e9f0b374efae01f4bbb2e1636dcb Mon Sep 17 00:00:00 2001 From: quexeky Date: Sat, 16 Nov 2024 17:03:37 +1100 Subject: [PATCH] feat(downloads): Added AgentInterfaceData to get information about all downloads in queue Signed-off-by: quexeky --- pages/store/index.vue | 2 +- src-tauri/src/downloads/download_agent.rs | 7 +- src-tauri/src/downloads/download_commands.rs | 10 +-- src-tauri/src/downloads/download_logic.rs | 2 +- src-tauri/src/downloads/download_manager.rs | 84 ++++++++++++++----- .../downloads/download_manager_interface.rs | 27 ++++-- src-tauri/src/lib.rs | 2 +- src-tauri/src/remote.rs | 8 +- 8 files changed, 98 insertions(+), 44 deletions(-) diff --git a/pages/store/index.vue b/pages/store/index.vue index ee5f7b2..18124ed 100644 --- a/pages/store/index.vue +++ b/pages/store/index.vue @@ -26,7 +26,7 @@ async function startGameDownload() { setInterval(() => { (async () => { const currentProgress = await invoke( - "get_game_download_progress", + "get_current_game_download_progress", { gameId: gameId.value, } diff --git a/src-tauri/src/downloads/download_agent.rs b/src-tauri/src/downloads/download_agent.rs index 7ef6f47..789d0fa 100644 --- a/src-tauri/src/downloads/download_agent.rs +++ b/src-tauri/src/downloads/download_agent.rs @@ -28,7 +28,7 @@ pub struct GameDownloadAgent { pub progress: ProgressObject, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum GameDownloadError { CommunicationError(RemoteAccessError), ChecksumError, @@ -50,11 +50,11 @@ impl Display for GameDownloadError { impl GameDownloadAgent { pub fn new(id: String, version: String, target_download_dir: usize) -> Self { // Don't run by default - let status = DownloadThreadControl::new(DownloadThreadControlFlag::Stop); + let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop); Self { id, version, - control_flag: status.clone(), + control_flag, manifest: Mutex::new(None), target_download_dir, contexts: Mutex::new(Vec::new()), @@ -207,6 +207,7 @@ impl GameDownloadAgent { .build() .unwrap(); + pool.scope(move |scope| { let contexts = self.contexts.lock().unwrap(); diff --git a/src-tauri/src/downloads/download_commands.rs b/src-tauri/src/downloads/download_commands.rs index 0a34e52..df48f4e 100644 --- a/src-tauri/src/downloads/download_commands.rs +++ b/src-tauri/src/downloads/download_commands.rs @@ -36,17 +36,9 @@ pub fn download_game( } #[tauri::command] -pub fn get_game_download_progress( +pub fn get_current_game_download_progress( state: tauri::State<'_, Mutex>, - game_id: String, ) -> Result { - /* - let download_agent = use_download_agent(state, game_id)?; - - let progress = &download_agent.progress; - - Ok(progress.get_progress()) - */ let progress = state .lock() .unwrap() diff --git a/src-tauri/src/downloads/download_logic.rs b/src-tauri/src/downloads/download_logic.rs index dc95f2f..9478b1e 100644 --- a/src-tauri/src/downloads/download_logic.rs +++ b/src-tauri/src/downloads/download_logic.rs @@ -148,7 +148,7 @@ pub fn download_game_chunk( .get(chunk_url) .header("Authorization", header) .send() - .map_err(|e| GameDownloadError::CommunicationError(RemoteAccessError::FetchError(e)))?; + .map_err(|e| GameDownloadError::CommunicationError(e.into()))?; let mut destination = DropWriter::new(ctx.path); diff --git a/src-tauri/src/downloads/download_manager.rs b/src-tauri/src/downloads/download_manager.rs index 378d989..330b983 100644 --- a/src-tauri/src/downloads/download_manager.rs +++ b/src-tauri/src/downloads/download_manager.rs @@ -10,8 +10,8 @@ use std::{ use log::info; use super::{ - download_agent::GameDownloadAgent, - download_manager_interface::DownloadManagerInterface, + download_agent::{GameDownloadAgent, GameDownloadError}, + download_manager_interface::{AgentInterfaceData, DownloadManagerInterface}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, progress_object::ProgressObject, }; @@ -55,12 +55,13 @@ Behold, my madness - quexeky pub struct DownloadManager { download_agent_registry: HashMap>, - download_queue: Arc>>, + download_queue: Arc>>>, command_receiver: Receiver, sender: Sender, progress: Arc>>, + status: Arc>, - current_game_id: Option, // Should be the only game download agent in the map with the "Go" flag + current_game_interface: Option>, // Should be the only game download agent in the map with the "Go" flag active_control_flag: Option, } pub enum DownloadManagerSignal { @@ -77,6 +78,21 @@ pub enum DownloadManagerSignal { /// Tells the Manager to stop the current /// download and return Finish, + /// Any error which occurs in the agent + Error(GameDownloadError) +} +pub enum DownloadManagerStatus { + Downloading, + Paused, + Empty, + Error(GameDownloadError), +} +#[derive(Clone)] +pub enum GameDownloadStatus { + Downloading, + Paused, + Uninitialised, + Error(GameDownloadError), } impl DownloadManager { @@ -84,13 +100,15 @@ impl DownloadManager { let queue = Arc::new(Mutex::new(VecDeque::new())); let (command_sender, command_receiver) = channel(); let active_progress = Arc::new(Mutex::new(None)); + let status = Arc::new(Mutex::new(DownloadManagerStatus::Empty)); let manager = Self { download_agent_registry: HashMap::new(), download_queue: queue.clone(), command_receiver, - current_game_id: None, + current_game_interface: None, active_control_flag: None, + status: status.clone(), sender: command_sender.clone(), progress: active_progress.clone(), }; @@ -110,6 +128,7 @@ impl DownloadManager { match signal { DownloadManagerSignal::Go => { self.manage_go_signal(); + } DownloadManagerSignal::Stop => { self.manage_stop_signal(); @@ -129,6 +148,9 @@ impl DownloadManager { } return Ok(()); } + DownloadManagerSignal::Error(game_download_error) => { + self.manage_error_signal(game_download_error); + }, }; } } @@ -142,12 +164,15 @@ impl DownloadManager { fn manage_completed_signal(&mut self, game_id: String) { info!("Got signal 'Completed'"); - if self.current_game_id == Some(game_id.clone()) { - info!("Popping consumed data"); - self.download_queue.lock().unwrap().pop_front(); - self.download_agent_registry.remove(&game_id); - self.active_control_flag = None; - *self.progress.lock().unwrap() = None; + if let Some(interface) = &self.current_game_interface { + // When if let chains are stabilised, combine these two statements + if interface.id == game_id { + info!("Popping consumed data"); + self.download_queue.lock().unwrap().pop_front(); + self.download_agent_registry.remove(&game_id); + self.active_control_flag = None; + *self.progress.lock().unwrap() = None; + } } self.sender.send(DownloadManagerSignal::Go).unwrap(); } @@ -164,9 +189,14 @@ impl DownloadManager { version, target_download_dir, )); + let agent_status = GameDownloadStatus::Uninitialised; + let interface_data = Arc::new(AgentInterfaceData { + id, + status: Mutex::new(agent_status), + }); self.download_agent_registry - .insert(id.clone(), download_agent); - self.download_queue.lock().unwrap().push_back(id); + .insert(interface_data.id.clone(), download_agent); + self.download_queue.lock().unwrap().push_back(interface_data); } fn manage_go_signal(&mut self) { @@ -176,11 +206,12 @@ impl DownloadManager { let download_agent = { let lock = self.download_queue.lock().unwrap(); self.download_agent_registry - .get(&lock.front().unwrap().clone()) + .get(&lock.front().unwrap().id) .unwrap() .clone() }; - self.current_game_id = Some(download_agent.id.clone()); + let download_agent_interface = Arc::new(AgentInterfaceData::from(download_agent.clone())); + self.current_game_interface = Some(download_agent_interface); let progress_object = download_agent.progress.clone(); *self.progress.lock().unwrap() = Some(progress_object); @@ -192,14 +223,20 @@ impl DownloadManager { info!("Spawning download"); spawn(move || { - download_agent.download().unwrap(); - sender - .send(DownloadManagerSignal::Completed(download_agent.id.clone())) - .unwrap(); + let signal = match download_agent.download() { + Ok(_) => { + DownloadManagerSignal::Completed(download_agent.id.clone()) + }, + Err(e) => { + DownloadManagerSignal::Error(e) + }, + }; + sender.send(signal).unwrap(); }); info!("Finished spawning Download"); active_control_flag.set(DownloadThreadControlFlag::Go); + self.set_status(DownloadManagerStatus::Downloading); } else if let Some(active_control_flag) = self.active_control_flag.clone() { info!("Restarting current download"); active_control_flag.set(DownloadThreadControlFlag::Go); @@ -207,4 +244,13 @@ impl DownloadManager { info!("Nothing was set"); } } + fn manage_error_signal(&self, error: GameDownloadError) { + let current_status = self.current_game_interface.clone().unwrap(); + let mut lock = current_status.status.lock().unwrap(); + *lock = GameDownloadStatus::Error(error.clone()); + self.set_status(DownloadManagerStatus::Error(error)); + } + fn set_status(&self, status: DownloadManagerStatus) { + *self.status.lock().unwrap() = status; + } } diff --git a/src-tauri/src/downloads/download_manager_interface.rs b/src-tauri/src/downloads/download_manager_interface.rs index 71e1779..d68c92b 100644 --- a/src-tauri/src/downloads/download_manager_interface.rs +++ b/src-tauri/src/downloads/download_manager_interface.rs @@ -7,7 +7,7 @@ use std::{ use log::info; -use super::{download_manager::DownloadManagerSignal, progress_object::ProgressObject}; +use super::{download_agent::GameDownloadAgent, download_manager::{DownloadManagerSignal, DownloadManagerStatus, GameDownloadStatus}, progress_object::ProgressObject}; /// Accessible front-end for the DownloadManager /// @@ -21,15 +21,27 @@ use super::{download_manager::DownloadManagerSignal, progress_object::ProgressOb /// THIS EDITING IS BLOCKING!!! pub struct DownloadManagerInterface { terminator: JoinHandle>, - download_queue: Arc>>, + download_queue: Arc>>>, progress: Arc>>, command_sender: Sender, } +pub struct AgentInterfaceData { + pub id: String, + pub status: Mutex, +} +impl From> for AgentInterfaceData { + fn from(value: Arc) -> Self { + Self { + id: value.id.clone(), + status: Mutex::from(GameDownloadStatus::Uninitialised) + } + } +} impl DownloadManagerInterface { pub fn new( terminator: JoinHandle>, - download_queue: Arc>>, + download_queue: Arc>>>, progress: Arc>>, command_sender: Sender, ) -> Self { @@ -55,9 +67,12 @@ impl DownloadManagerInterface { ))?; self.command_sender.send(DownloadManagerSignal::Go) } - pub fn edit(&self) -> MutexGuard<'_, VecDeque> { + pub fn edit(&self) -> MutexGuard<'_, VecDeque>> { self.download_queue.lock().unwrap() } + pub fn read_queue(&self) -> VecDeque> { + self.download_queue.lock().unwrap().clone() + } pub fn get_current_game_download_progress(&self) -> Option { let progress_object = (*self.progress.lock().unwrap()).clone()?; Some(progress_object.get_progress()) @@ -95,8 +110,8 @@ impl DownloadManagerInterface { /// Takes in the locked value from .edit() and attempts to /// get the index of whatever game_id is passed in -fn get_index_from_id(queue: &mut MutexGuard<'_, VecDeque>, id: String) -> Option { +fn get_index_from_id(queue: &mut MutexGuard<'_, VecDeque>>, id: String) -> Option { queue .iter() - .position(|download_agent| download_agent == &id) + .position(|download_agent| download_agent.id == id) } diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6574c7c..8982d9d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -124,7 +124,7 @@ pub fn run() { add_new_download_dir, // Downloads download_game, - get_game_download_progress, + get_current_game_download_progress, ]) .plugin(tauri_plugin_shell::init()) .setup(|app| { diff --git a/src-tauri/src/remote.rs b/src-tauri/src/remote.rs index e415c52..303a3db 100644 --- a/src-tauri/src/remote.rs +++ b/src-tauri/src/remote.rs @@ -1,6 +1,6 @@ use std::{ fmt::{Display, Formatter}, - sync::Mutex, + sync::{Arc, Mutex}, }; use log::{info, warn}; @@ -9,9 +9,9 @@ use url::{ParseError, Url}; use crate::{AppState, AppStatus, DB}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum RemoteAccessError { - FetchError(reqwest::Error), + FetchError(Arc), ParsingError(ParseError), InvalidCodeError(u16), GenericErrror(String), @@ -32,7 +32,7 @@ impl Display for RemoteAccessError { impl From for RemoteAccessError { fn from(err: reqwest::Error) -> Self { - RemoteAccessError::FetchError(err) + RemoteAccessError::FetchError(Arc::new(err)) } } impl From for RemoteAccessError {