From aed58e49bcf85e4f09348fa24363d3593a754ebe Mon Sep 17 00:00:00 2001 From: quexeky Date: Tue, 31 Dec 2024 12:12:17 +1100 Subject: [PATCH] refactor(download manager): Renamed GameDonwloadError to ApplicationDownloadError and moved Signed-off-by: quexeky --- .../application_download_error.rs | 41 ++++++++++++++ .../src/download_manager/download_manager.rs | 26 +++++++-- .../download_manager_builder.rs | 24 ++++---- .../src/download_manager/downloadable.rs | 7 +-- src-tauri/src/download_manager/mod.rs | 3 +- src-tauri/src/downloads/download_agent.rs | 56 ++++--------------- src-tauri/src/downloads/download_logic.rs | 18 +++--- 7 files changed, 98 insertions(+), 77 deletions(-) create mode 100644 src-tauri/src/download_manager/application_download_error.rs diff --git a/src-tauri/src/download_manager/application_download_error.rs b/src-tauri/src/download_manager/application_download_error.rs new file mode 100644 index 0000000..38c690d --- /dev/null +++ b/src-tauri/src/download_manager/application_download_error.rs @@ -0,0 +1,41 @@ +use std::{fmt::{Display, Formatter}, io}; + +use crate::remote::RemoteAccessError; + +// TODO: Rename / separate from downloads +#[derive(Debug, Clone)] +pub enum ApplicationDownloadError { + Communication(RemoteAccessError), + Checksum, + Setup(SetupError), + Lock, + IoError(io::ErrorKind), + DownloadError, +} + +impl Display for ApplicationDownloadError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + ApplicationDownloadError::Communication(error) => write!(f, "{}", error), + ApplicationDownloadError::Setup(error) => write!(f, "An error occurred while setting up the download: {}", error), + ApplicationDownloadError::Lock => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"), + ApplicationDownloadError::Checksum => write!(f, "Checksum failed to validate for download"), + ApplicationDownloadError::IoError(error) => write!(f, "{}", error), + ApplicationDownloadError::DownloadError => write!(f, "Download failed. See Download Manager status for specific error"), + } + } +} + +#[derive(Debug, Clone)] +pub enum SetupError { + Context, +} + +impl Display for SetupError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + SetupError::Context => write!(f, "Failed to generate contexts for download"), + } + } +} + diff --git a/src-tauri/src/download_manager/download_manager.rs b/src-tauri/src/download_manager/download_manager.rs index ede48e1..230646a 100644 --- a/src-tauri/src/download_manager/download_manager.rs +++ b/src-tauri/src/download_manager/download_manager.rs @@ -12,14 +12,32 @@ use std::{ use log::info; use serde::Serialize; -use crate::downloads::download_agent::GameDownloadError; +use crate::downloads::download_agent::{GameDownloadAgent}; -use super::{download_manager_builder::{CurrentProgressObject, DownloadableQueueStandin}, downloadable::Downloadable, queue::Queue}; +use super::{application_download_error::ApplicationDownloadError, download_manager_builder::{CurrentProgressObject, DownloadableQueueStandin}, downloadable::Downloadable, queue::Queue}; pub enum DownloadType { Game, Tool, } +impl DownloadType { + pub fn generate( + &self, + id: String, + version: String, + target_download_dir: usize, + sender: Sender) -> Box { + return Box::new(match self { + DownloadType::Game => GameDownloadAgent::new( + id.clone(), + version, + target_download_dir, + sender.clone(), + ), + DownloadType::Tool => todo!(), + }) + } +} pub enum DownloadManagerSignal { /// Resumes (or starts) the DownloadManager @@ -40,7 +58,7 @@ pub enum DownloadManagerSignal { /// Removes a given application Remove(String), /// Any error which occurs in the agent - Error(GameDownloadError), + Error(ApplicationDownloadError), /// Pushes UI update UpdateUIQueue, UpdateUIStats(usize, usize), //kb/s and seconds @@ -54,7 +72,7 @@ pub enum DownloadManagerStatus { Downloading, Paused, Empty, - Error(GameDownloadError), + Error(ApplicationDownloadError), Finished, } diff --git a/src-tauri/src/download_manager/download_manager_builder.rs b/src-tauri/src/download_manager/download_manager_builder.rs index c36867b..caf80f9 100644 --- a/src-tauri/src/download_manager/download_manager_builder.rs +++ b/src-tauri/src/download_manager/download_manager_builder.rs @@ -12,13 +12,13 @@ use log::{error, info}; use tauri::{AppHandle, Emitter}; use crate::{ - db::{Database, ApplicationStatus, ApplicationTransientStatus}, download_manager::download_manager::DownloadStatus, downloads::download_agent::{GameDownloadAgent, GameDownloadError}, library::{ + db::{ApplicationStatus, ApplicationTransientStatus, Database}, download_manager::download_manager::{DownloadStatus, DownloadType}, downloads::download_agent::{GameDownloadAgent}, library::{ on_game_complete, push_application_update, QueueUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent, }, state::GameStatusManager, DB }; -use super::{download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, downloadable::Downloadable, progress_object::ProgressObject, queue::Queue}; +use super::{application_download_error::ApplicationDownloadError, download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, downloadable::Downloadable, progress_object::ProgressObject, queue::Queue}; /* @@ -59,7 +59,7 @@ Behold, my madness - quexeky // Refactored to consolidate this type. It's a monster. pub type CurrentProgressObject = Arc>>>; -pub type DownloadAgent = Arc>; +pub type DownloadAgent = Arc>>; pub struct DownloadManagerBuilder { download_agent_registry: HashMap, @@ -272,7 +272,7 @@ impl DownloadManagerBuilder { spawn(move || match remove_dir_all(install_dir) { Err(e) => { sender - .send(DownloadManagerSignal::Error(GameDownloadError::IoError( + .send(DownloadManagerSignal::Error(ApplicationDownloadError::IoError( e.kind(), ))) .unwrap(); @@ -345,8 +345,11 @@ impl DownloadManagerBuilder { if let Err(error) = on_game_complete(id, version, install_dir, &self.app_handle) { - error!("failed to mark game as completed: {}", error); - // TODO mark game as remote so user can retry + self.sender + .send(DownloadManagerSignal::Error( + ApplicationDownloadError::Communication(error), + )) + .unwrap(); } } } @@ -374,7 +377,7 @@ impl DownloadManagerBuilder { } } - let download_agent = Arc::new(Mutex::new(GameDownloadAgent::new( + let download_agent = Arc::new(Mutex::new(DownloadType::Game.generate( id.clone(), version, target_download_dir, @@ -386,9 +389,9 @@ impl DownloadManagerBuilder { let interface_data = DownloadableQueueStandin { id: id.clone(), status: Mutex::new(agent_status), - progress: download_agent_lock.progress.clone(), + progress: download_agent_lock.progress() }; - let version_name = download_agent_lock.version.clone(); + let version_name = download_agent_lock.version().clone(); drop(download_agent_lock); @@ -485,8 +488,7 @@ impl DownloadManagerBuilder { .send(DownloadManagerSignal::UpdateUIQueue) .unwrap(); } - fn manage_error_signal(&mut self, error: GameDownloadError) { - error!("{}", error); + fn manage_error_signal(&mut self, error: ApplicationDownloadError) { let current_status = self.current_download_agent.clone().unwrap(); self.stop_and_wait_current_download(); diff --git a/src-tauri/src/download_manager/downloadable.rs b/src-tauri/src/download_manager/downloadable.rs index 52f57d2..fb280a9 100644 --- a/src-tauri/src/download_manager/downloadable.rs +++ b/src-tauri/src/download_manager/downloadable.rs @@ -1,17 +1,14 @@ use std::sync::Arc; -use crate::downloads::download_agent::GameDownloadError; - use super::{ - download_thread_control_flag::DownloadThreadControl, - progress_object::ProgressObject, + application_download_error::ApplicationDownloadError, download_thread_control_flag::DownloadThreadControl, progress_object::ProgressObject }; pub trait Downloadable: Sync { fn get_progress_object(&self) -> Arc; fn version(&self) -> String; fn id(&self) -> String; - fn download(&mut self) -> Result<(), GameDownloadError>; + fn download(&mut self) -> Result<(), ApplicationDownloadError>; fn progress(&self) -> Arc; fn control_flag(&self) -> DownloadThreadControl; fn install_dir(&self) -> String; diff --git a/src-tauri/src/download_manager/mod.rs b/src-tauri/src/download_manager/mod.rs index 1d5ee1f..66e7d9d 100644 --- a/src-tauri/src/download_manager/mod.rs +++ b/src-tauri/src/download_manager/mod.rs @@ -3,4 +3,5 @@ pub mod download_manager_builder; pub mod progress_object; pub mod queue; pub mod download_thread_control_flag; -pub mod downloadable; \ No newline at end of file +pub mod downloadable; +pub mod application_download_error; \ No newline at end of file diff --git a/src-tauri/src/downloads/download_agent.rs b/src-tauri/src/downloads/download_agent.rs index 8bb7cfe..ed7a975 100644 --- a/src-tauri/src/downloads/download_agent.rs +++ b/src-tauri/src/downloads/download_agent.rs @@ -1,5 +1,6 @@ use crate::auth::generate_authorization_header; use crate::db::DatabaseImpls; +use crate::download_manager::application_download_error::ApplicationDownloadError; use crate::download_manager::download_manager::{DownloadManagerSignal, DownloadStatus}; use crate::download_manager::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}; use crate::download_manager::downloadable::Downloadable; @@ -37,42 +38,7 @@ pub struct GameDownloadAgent { pub stored_manifest: StoredManifest, } -// TODO: Rename / separate from downloads -#[derive(Debug, Clone)] -pub enum GameDownloadError { - Communication(RemoteAccessError), - Checksum, - Setup(SetupError), - Lock, - IoError(io::ErrorKind), - DownloadError, -} -#[derive(Debug, Clone)] -pub enum SetupError { - Context, -} - -impl Display for GameDownloadError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - GameDownloadError::Communication(error) => write!(f, "{}", error), - GameDownloadError::Setup(error) => write!(f, "An error occurred while setting up the download: {}", error), - GameDownloadError::Lock => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"), - GameDownloadError::Checksum => write!(f, "Checksum failed to validate for download"), - GameDownloadError::IoError(error) => write!(f, "{}", error), - GameDownloadError::DownloadError => write!(f, "Download failed. See Download Manager status for specific error"), - } - } -} - -impl Display for SetupError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - SetupError::Context => write!(f, "Failed to generate contexts for download"), - } - } -} impl GameDownloadAgent { pub fn new( @@ -108,7 +74,7 @@ impl GameDownloadAgent { } // Blocking - pub fn setup_download(&mut self) -> Result<(), GameDownloadError> { + pub fn setup_download(&mut self) -> Result<(), ApplicationDownloadError> { self.ensure_manifest_exists()?; info!("Ensured manifest exists"); @@ -121,11 +87,11 @@ impl GameDownloadAgent { } // Blocking - pub fn download(&mut self) -> Result<(), GameDownloadError> { + pub fn download(&mut self) -> Result<(), ApplicationDownloadError> { self.setup_download()?; self.set_progress_object_params(); let timer = Instant::now(); - self.run().map_err(|_| GameDownloadError::DownloadError)?; + self.run().map_err(|_| ApplicationDownloadError::DownloadError)?; info!( "{} took {}ms to download", @@ -135,7 +101,7 @@ impl GameDownloadAgent { Ok(()) } - pub fn ensure_manifest_exists(&self) -> Result<(), GameDownloadError> { + pub fn ensure_manifest_exists(&self) -> Result<(), ApplicationDownloadError> { if self.manifest.lock().unwrap().is_some() { return Ok(()); } @@ -143,7 +109,7 @@ impl GameDownloadAgent { self.download_manifest() } - fn download_manifest(&self) -> Result<(), GameDownloadError> { + fn download_manifest(&self) -> Result<(), ApplicationDownloadError> { let base_url = DB.fetch_base_url(); let manifest_url = base_url .join( @@ -165,7 +131,7 @@ impl GameDownloadAgent { .unwrap(); if response.status() != 200 { - return Err(GameDownloadError::Communication( + return Err(ApplicationDownloadError::Communication( RemoteAccessError::ManifestDownloadFailed( response.status(), response.text().unwrap(), @@ -180,7 +146,7 @@ impl GameDownloadAgent { return Ok(()); } - Err(GameDownloadError::Lock) + Err(ApplicationDownloadError::Lock) } fn set_progress_object_params(&self) { @@ -201,7 +167,7 @@ impl GameDownloadAgent { self.progress.set_time_now(); } - pub fn ensure_contexts(&mut self) -> Result<(), GameDownloadError> { + pub fn ensure_contexts(&mut self) -> Result<(), ApplicationDownloadError> { if !self.contexts.is_empty() { return Ok(()); } @@ -210,7 +176,7 @@ impl GameDownloadAgent { Ok(()) } - pub fn generate_contexts(&mut self) -> Result<(), GameDownloadError> { + pub fn generate_contexts(&mut self) -> Result<(), ApplicationDownloadError> { let manifest = self.manifest.lock().unwrap().clone().unwrap(); let game_id = self.id.clone(); @@ -340,7 +306,7 @@ impl Downloadable for GameDownloadAgent { self.id.clone() } - fn download(&mut self) -> Result<(), GameDownloadError> { + fn download(&mut self) -> Result<(), ApplicationDownloadError> { self.download() } diff --git a/src-tauri/src/downloads/download_logic.rs b/src-tauri/src/downloads/download_logic.rs index 0d6f67f..de0f615 100644 --- a/src-tauri/src/downloads/download_logic.rs +++ b/src-tauri/src/downloads/download_logic.rs @@ -1,5 +1,6 @@ use crate::auth::generate_authorization_header; use crate::db::DatabaseImpls; +use crate::download_manager::application_download_error::ApplicationDownloadError; use crate::download_manager::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}; use crate::download_manager::progress_object::ProgressHandle; use crate::downloads::manifest::DropDownloadContext; @@ -21,8 +22,6 @@ use std::{ }; use urlencoding::encode; -use super::download_agent::GameDownloadError; - pub struct DropWriter { hasher: Context, destination: W, @@ -125,7 +124,7 @@ pub fn download_game_chunk( ctx: DropDownloadContext, control_flag: DownloadThreadControl, progress: ProgressHandle, -) -> Result { +) -> Result { // If we're paused if control_flag.get() == DownloadThreadControlFlag::Stop { progress.set(0); @@ -152,11 +151,11 @@ pub fn download_game_chunk( .get(chunk_url) .header("Authorization", header) .send() - .map_err(|e| GameDownloadError::Communication(e.into()))?; + .map_err(|e| ApplicationDownloadError::Communication(e.into()))?; if response.status() != 200 { warn!("{}", response.text().unwrap()); - return Err(GameDownloadError::Communication( + return Err(ApplicationDownloadError::Communication( RemoteAccessError::InvalidCodeError(400), )); } @@ -171,11 +170,8 @@ pub fn download_game_chunk( let content_length = response.content_length(); if content_length.is_none() { - return Err(GameDownloadError::Communication( - RemoteAccessError::ManifestDownloadFailed( - StatusCode::from_u16(500).unwrap(), - "failed to download manifest due to missing content length".to_owned(), - ), + return Err(ApplicationDownloadError::Communication( + RemoteAccessError::InvalidResponse, )); } @@ -189,7 +185,7 @@ pub fn download_game_chunk( let completed = pipeline .copy() - .map_err(|e| GameDownloadError::IoError(e.kind()))?; + .map_err(|e| ApplicationDownloadError::IoError(e.kind()))?; if !completed { return Ok(false); };