refactor(download manager): Renamed GameDonwloadError to ApplicationDownloadError and moved

Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
quexeky
2024-12-31 12:12:17 +11:00
parent 881fcc6abe
commit aed58e49bc
7 changed files with 98 additions and 77 deletions

View File

@ -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"),
}
}
}

View File

@ -12,14 +12,32 @@ use std::{
use log::info; use log::info;
use serde::Serialize; 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 { pub enum DownloadType {
Game, Game,
Tool, Tool,
} }
impl DownloadType {
pub fn generate(
&self,
id: String,
version: String,
target_download_dir: usize,
sender: Sender<DownloadManagerSignal>) -> Box<dyn Downloadable + Send + Sync> {
return Box::new(match self {
DownloadType::Game => GameDownloadAgent::new(
id.clone(),
version,
target_download_dir,
sender.clone(),
),
DownloadType::Tool => todo!(),
})
}
}
pub enum DownloadManagerSignal { pub enum DownloadManagerSignal {
/// Resumes (or starts) the DownloadManager /// Resumes (or starts) the DownloadManager
@ -40,7 +58,7 @@ pub enum DownloadManagerSignal {
/// Removes a given application /// Removes a given application
Remove(String), Remove(String),
/// Any error which occurs in the agent /// Any error which occurs in the agent
Error(GameDownloadError), Error(ApplicationDownloadError),
/// Pushes UI update /// Pushes UI update
UpdateUIQueue, UpdateUIQueue,
UpdateUIStats(usize, usize), //kb/s and seconds UpdateUIStats(usize, usize), //kb/s and seconds
@ -54,7 +72,7 @@ pub enum DownloadManagerStatus {
Downloading, Downloading,
Paused, Paused,
Empty, Empty,
Error(GameDownloadError), Error(ApplicationDownloadError),
Finished, Finished,
} }

View File

@ -12,13 +12,13 @@ use log::{error, info};
use tauri::{AppHandle, Emitter}; use tauri::{AppHandle, Emitter};
use crate::{ 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, on_game_complete, push_application_update, QueueUpdateEvent,
QueueUpdateEventQueueData, StatsUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent,
}, state::GameStatusManager, DB }, 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. // Refactored to consolidate this type. It's a monster.
pub type CurrentProgressObject = Arc<Mutex<Option<Arc<ProgressObject>>>>; pub type CurrentProgressObject = Arc<Mutex<Option<Arc<ProgressObject>>>>;
pub type DownloadAgent = Arc<Mutex<dyn Downloadable + Send + Sync>>; pub type DownloadAgent = Arc<Mutex<Box<dyn Downloadable + Send + Sync>>>;
pub struct DownloadManagerBuilder { pub struct DownloadManagerBuilder {
download_agent_registry: HashMap<String, DownloadAgent>, download_agent_registry: HashMap<String, DownloadAgent>,
@ -272,7 +272,7 @@ impl DownloadManagerBuilder {
spawn(move || match remove_dir_all(install_dir) { spawn(move || match remove_dir_all(install_dir) {
Err(e) => { Err(e) => {
sender sender
.send(DownloadManagerSignal::Error(GameDownloadError::IoError( .send(DownloadManagerSignal::Error(ApplicationDownloadError::IoError(
e.kind(), e.kind(),
))) )))
.unwrap(); .unwrap();
@ -345,8 +345,11 @@ impl DownloadManagerBuilder {
if let Err(error) = if let Err(error) =
on_game_complete(id, version, install_dir, &self.app_handle) on_game_complete(id, version, install_dir, &self.app_handle)
{ {
error!("failed to mark game as completed: {}", error); self.sender
// TODO mark game as remote so user can retry .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(), id.clone(),
version, version,
target_download_dir, target_download_dir,
@ -386,9 +389,9 @@ impl DownloadManagerBuilder {
let interface_data = DownloadableQueueStandin { let interface_data = DownloadableQueueStandin {
id: id.clone(), id: id.clone(),
status: Mutex::new(agent_status), 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); drop(download_agent_lock);
@ -485,8 +488,7 @@ impl DownloadManagerBuilder {
.send(DownloadManagerSignal::UpdateUIQueue) .send(DownloadManagerSignal::UpdateUIQueue)
.unwrap(); .unwrap();
} }
fn manage_error_signal(&mut self, error: GameDownloadError) { fn manage_error_signal(&mut self, error: ApplicationDownloadError) {
error!("{}", error);
let current_status = self.current_download_agent.clone().unwrap(); let current_status = self.current_download_agent.clone().unwrap();
self.stop_and_wait_current_download(); self.stop_and_wait_current_download();

View File

@ -1,17 +1,14 @@
use std::sync::Arc; use std::sync::Arc;
use crate::downloads::download_agent::GameDownloadError;
use super::{ use super::{
download_thread_control_flag::DownloadThreadControl, application_download_error::ApplicationDownloadError, download_thread_control_flag::DownloadThreadControl, progress_object::ProgressObject
progress_object::ProgressObject,
}; };
pub trait Downloadable: Sync { pub trait Downloadable: Sync {
fn get_progress_object(&self) -> Arc<ProgressObject>; fn get_progress_object(&self) -> Arc<ProgressObject>;
fn version(&self) -> String; fn version(&self) -> String;
fn id(&self) -> String; fn id(&self) -> String;
fn download(&mut self) -> Result<(), GameDownloadError>; fn download(&mut self) -> Result<(), ApplicationDownloadError>;
fn progress(&self) -> Arc<ProgressObject>; fn progress(&self) -> Arc<ProgressObject>;
fn control_flag(&self) -> DownloadThreadControl; fn control_flag(&self) -> DownloadThreadControl;
fn install_dir(&self) -> String; fn install_dir(&self) -> String;

View File

@ -3,4 +3,5 @@ pub mod download_manager_builder;
pub mod progress_object; pub mod progress_object;
pub mod queue; pub mod queue;
pub mod download_thread_control_flag; pub mod download_thread_control_flag;
pub mod downloadable; pub mod downloadable;
pub mod application_download_error;

View File

@ -1,5 +1,6 @@
use crate::auth::generate_authorization_header; use crate::auth::generate_authorization_header;
use crate::db::DatabaseImpls; 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_manager::{DownloadManagerSignal, DownloadStatus};
use crate::download_manager::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}; use crate::download_manager::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
use crate::download_manager::downloadable::Downloadable; use crate::download_manager::downloadable::Downloadable;
@ -37,42 +38,7 @@ pub struct GameDownloadAgent {
pub stored_manifest: StoredManifest, 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 { impl GameDownloadAgent {
pub fn new( pub fn new(
@ -108,7 +74,7 @@ impl GameDownloadAgent {
} }
// Blocking // Blocking
pub fn setup_download(&mut self) -> Result<(), GameDownloadError> { pub fn setup_download(&mut self) -> Result<(), ApplicationDownloadError> {
self.ensure_manifest_exists()?; self.ensure_manifest_exists()?;
info!("Ensured manifest exists"); info!("Ensured manifest exists");
@ -121,11 +87,11 @@ impl GameDownloadAgent {
} }
// Blocking // Blocking
pub fn download(&mut self) -> Result<(), GameDownloadError> { pub fn download(&mut self) -> Result<(), ApplicationDownloadError> {
self.setup_download()?; self.setup_download()?;
self.set_progress_object_params(); self.set_progress_object_params();
let timer = Instant::now(); let timer = Instant::now();
self.run().map_err(|_| GameDownloadError::DownloadError)?; self.run().map_err(|_| ApplicationDownloadError::DownloadError)?;
info!( info!(
"{} took {}ms to download", "{} took {}ms to download",
@ -135,7 +101,7 @@ impl GameDownloadAgent {
Ok(()) Ok(())
} }
pub fn ensure_manifest_exists(&self) -> Result<(), GameDownloadError> { pub fn ensure_manifest_exists(&self) -> Result<(), ApplicationDownloadError> {
if self.manifest.lock().unwrap().is_some() { if self.manifest.lock().unwrap().is_some() {
return Ok(()); return Ok(());
} }
@ -143,7 +109,7 @@ impl GameDownloadAgent {
self.download_manifest() self.download_manifest()
} }
fn download_manifest(&self) -> Result<(), GameDownloadError> { fn download_manifest(&self) -> Result<(), ApplicationDownloadError> {
let base_url = DB.fetch_base_url(); let base_url = DB.fetch_base_url();
let manifest_url = base_url let manifest_url = base_url
.join( .join(
@ -165,7 +131,7 @@ impl GameDownloadAgent {
.unwrap(); .unwrap();
if response.status() != 200 { if response.status() != 200 {
return Err(GameDownloadError::Communication( return Err(ApplicationDownloadError::Communication(
RemoteAccessError::ManifestDownloadFailed( RemoteAccessError::ManifestDownloadFailed(
response.status(), response.status(),
response.text().unwrap(), response.text().unwrap(),
@ -180,7 +146,7 @@ impl GameDownloadAgent {
return Ok(()); return Ok(());
} }
Err(GameDownloadError::Lock) Err(ApplicationDownloadError::Lock)
} }
fn set_progress_object_params(&self) { fn set_progress_object_params(&self) {
@ -201,7 +167,7 @@ impl GameDownloadAgent {
self.progress.set_time_now(); 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() { if !self.contexts.is_empty() {
return Ok(()); return Ok(());
} }
@ -210,7 +176,7 @@ impl GameDownloadAgent {
Ok(()) 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 manifest = self.manifest.lock().unwrap().clone().unwrap();
let game_id = self.id.clone(); let game_id = self.id.clone();
@ -340,7 +306,7 @@ impl Downloadable for GameDownloadAgent {
self.id.clone() self.id.clone()
} }
fn download(&mut self) -> Result<(), GameDownloadError> { fn download(&mut self) -> Result<(), ApplicationDownloadError> {
self.download() self.download()
} }

View File

@ -1,5 +1,6 @@
use crate::auth::generate_authorization_header; use crate::auth::generate_authorization_header;
use crate::db::DatabaseImpls; 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::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
use crate::download_manager::progress_object::ProgressHandle; use crate::download_manager::progress_object::ProgressHandle;
use crate::downloads::manifest::DropDownloadContext; use crate::downloads::manifest::DropDownloadContext;
@ -21,8 +22,6 @@ use std::{
}; };
use urlencoding::encode; use urlencoding::encode;
use super::download_agent::GameDownloadError;
pub struct DropWriter<W: Write> { pub struct DropWriter<W: Write> {
hasher: Context, hasher: Context,
destination: W, destination: W,
@ -125,7 +124,7 @@ pub fn download_game_chunk(
ctx: DropDownloadContext, ctx: DropDownloadContext,
control_flag: DownloadThreadControl, control_flag: DownloadThreadControl,
progress: ProgressHandle, progress: ProgressHandle,
) -> Result<bool, GameDownloadError> { ) -> Result<bool, ApplicationDownloadError> {
// If we're paused // If we're paused
if control_flag.get() == DownloadThreadControlFlag::Stop { if control_flag.get() == DownloadThreadControlFlag::Stop {
progress.set(0); progress.set(0);
@ -152,11 +151,11 @@ pub fn download_game_chunk(
.get(chunk_url) .get(chunk_url)
.header("Authorization", header) .header("Authorization", header)
.send() .send()
.map_err(|e| GameDownloadError::Communication(e.into()))?; .map_err(|e| ApplicationDownloadError::Communication(e.into()))?;
if response.status() != 200 { if response.status() != 200 {
warn!("{}", response.text().unwrap()); warn!("{}", response.text().unwrap());
return Err(GameDownloadError::Communication( return Err(ApplicationDownloadError::Communication(
RemoteAccessError::InvalidCodeError(400), RemoteAccessError::InvalidCodeError(400),
)); ));
} }
@ -171,11 +170,8 @@ pub fn download_game_chunk(
let content_length = response.content_length(); let content_length = response.content_length();
if content_length.is_none() { if content_length.is_none() {
return Err(GameDownloadError::Communication( return Err(ApplicationDownloadError::Communication(
RemoteAccessError::ManifestDownloadFailed( RemoteAccessError::InvalidResponse,
StatusCode::from_u16(500).unwrap(),
"failed to download manifest due to missing content length".to_owned(),
),
)); ));
} }
@ -189,7 +185,7 @@ pub fn download_game_chunk(
let completed = pipeline let completed = pipeline
.copy() .copy()
.map_err(|e| GameDownloadError::IoError(e.kind()))?; .map_err(|e| ApplicationDownloadError::IoError(e.kind()))?;
if !completed { if !completed {
return Ok(false); return Ok(false);
}; };