From 06d1e9ed95d7f40a99d5d59d815f04a768c504fe Mon Sep 17 00:00:00 2001 From: quexeky Date: Sat, 4 Jan 2025 18:34:47 +1100 Subject: [PATCH] refactor(downloads): Moved all files relevant to game downloads to their own directory Signed-off-by: quexeky --- src-tauri/src/db.rs | 2 +- .../download_manager_builder.rs | 511 +----------------- .../{ => games}/downloads/download_agent.rs | 4 +- .../downloads/download_commands.rs | 0 .../{ => games}/downloads/download_logic.rs | 2 +- .../src/{ => games}/downloads/manifest.rs | 0 src-tauri/src/{ => games}/downloads/mod.rs | 2 +- .../{ => games}/downloads/stored_manifest.rs | 0 src-tauri/src/{ => games}/library.rs | 5 +- src-tauri/src/games/mod.rs | 3 + src-tauri/src/{ => games}/state.rs | 0 src-tauri/src/lib.rs | 10 +- src-tauri/src/process/process_manager.rs | 2 +- 13 files changed, 15 insertions(+), 526 deletions(-) rename src-tauri/src/{ => games}/downloads/download_agent.rs (98%) rename src-tauri/src/{ => games}/downloads/download_commands.rs (100%) rename src-tauri/src/{ => games}/downloads/download_logic.rs (98%) rename src-tauri/src/{ => games}/downloads/manifest.rs (100%) rename src-tauri/src/{ => games}/downloads/mod.rs (80%) rename src-tauri/src/{ => games}/downloads/stored_manifest.rs (100%) rename src-tauri/src/{ => games}/library.rs (98%) create mode 100644 src-tauri/src/games/mod.rs rename src-tauri/src/{ => games}/state.rs (100%) diff --git a/src-tauri/src/db.rs b/src-tauri/src/db.rs index d26a37b..ad4f4f6 100644 --- a/src-tauri/src/db.rs +++ b/src-tauri/src/db.rs @@ -13,7 +13,7 @@ use serde_with::serde_as; use tauri::AppHandle; use url::Url; -use crate::{download_manager::downloadable_metadata::DownloadableMetadata, library::push_game_update, process::process_manager::Platform, state::GameStatusManager, DB}; +use crate::{download_manager::downloadable_metadata::DownloadableMetadata, games::{library::push_game_update, state::GameStatusManager}, process::process_manager::Platform, DB}; #[derive(serde::Serialize, Clone, Deserialize)] pub struct DatabaseAuth { diff --git a/src-tauri/src/download_manager/download_manager_builder.rs b/src-tauri/src/download_manager/download_manager_builder.rs index 6acb37e..eeaaeae 100644 --- a/src-tauri/src/download_manager/download_manager_builder.rs +++ b/src-tauri/src/download_manager/download_manager_builder.rs @@ -11,9 +11,7 @@ use std::{ use log::{error, info}; use tauri::{AppHandle, Emitter}; -use crate::{ - download_manager::{download_manager::DownloadStatus, generate_downloadable::generate_downloadable}, library::{QueueUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent}} -; +use crate::games::library::{QueueUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent}; use super::{application_download_error::ApplicationDownloadError, download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, downloadable::Downloadable, downloadable_metadata::DownloadableMetadata, progress_object::ProgressObject, queue::Queue}; @@ -341,509 +339,4 @@ impl DownloadManagerBuilder { }; self.app_handle.emit("update_queue", event_data).unwrap(); } -} -/* -// Refactored to consolidate this type. It's a monster. -pub type DownloadAgent = Arc>>; - - -impl DownloadManagerBuilder { - 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() - .map(|interface| QueueUpdateEventQueueData { - id: interface.id.clone(), - status: interface.status.lock().unwrap().clone(), - progress: interface.progress.get_progress(), - }) - .collect(); - - let status_handle = self.status.lock().unwrap(); - let status = status_handle.clone(); - drop(status_handle); - - let event_data = QueueUpdateEvent { - queue: queue_objs, - status, - }; - self.app_handle.emit("update_queue", event_data).unwrap(); - } - fn uninstall_application(&mut self, id: String) { - // Removes the download if it's in the queue - self.manage_remove_download_from_queue(id.clone()); - - let mut db_handle = DB.borrow_data_mut().unwrap(); - db_handle - .applications - .transient_statuses - .entry(id.clone()) - .and_modify(|v| *v = ApplicationTransientStatus::Uninstalling {}); - push_application_update( - &self.app_handle, - id.clone(), - (None, Some(ApplicationTransientStatus::Uninstalling {})), - ); - - let previous_state = db_handle.applications.statuses.get(&id).cloned(); - if previous_state.is_none() { - info!("uninstall job doesn't have previous state, failing silently"); - return; - } - let previous_state = previous_state.unwrap(); - if let Some((_version_name, install_dir)) = match previous_state { - ApplicationStatus::Installed { - version_name, - install_dir, - } => Some((version_name, install_dir)), - ApplicationStatus::SetupRequired { - version_name, - install_dir, - } => Some((version_name, install_dir)), - _ => None, - } { - db_handle - .applications - .transient_statuses - .entry(id.clone()) - .and_modify(|v| *v = ApplicationTransientStatus::Uninstalling {}); - drop(db_handle); - - let sender = self.sender.clone(); - let app_handle = self.app_handle.clone(); - spawn(move || match remove_dir_all(install_dir) { - Err(e) => { - sender - .send(DownloadManagerSignal::Error(ApplicationDownloadError::IoError( - e.kind(), - ))) - .unwrap(); - } - Ok(_) => { - let mut db_handle = DB.borrow_data_mut().unwrap(); - db_handle.applications.transient_statuses.remove(&id); - db_handle - .applications - .statuses - .entry(id.clone()) - .and_modify(|e| *e = ApplicationStatus::Remote {}); - drop(db_handle); - DB.save().unwrap(); - - info!("uninstalled {}", id); - - push_application_update(&app_handle, id, (Some(ApplicationStatus::Remote {}), None)); - } - }); - } - } - fn manage_remove_download_from_queue(&mut self, id: DownloadableMetadata) { - if let Some(current_download) = &self.current_download_agent { - if current_download.lock().unwrap().metadata() == id { - self.manage_cancel_signal(); - } - } - - let index = self.download_queue.get_by_id(id.clone()); - if let Some(index) = index { - let mut queue_handle = self.download_queue.edit(); - queue_handle.remove(index); - set_application_status(&self.app_handle, id, |db_handle, id| { - db_handle.applications.transient_statuses.remove(id); - }); - drop(queue_handle); - } - - if self.current_download_agent.is_none() { - self.manage_go_signal(); - } - - self.push_ui_queue_update(); - } - - fn manage_cancel_signal(&mut self) { - self.stop_and_wait_current_download(); - - info!("cancel waited for download to finish"); - - self.cleanup_current_download(); - } - - fn manage_error_signal(&mut self, error: ApplicationDownloadError) { - let current_status = self.current_download_agent.clone().unwrap(); - - self.stop_and_wait_current_download(); - self.remove_and_cleanup_front_download(¤t_status.id); // Remove all the locks and shit, and remove from queue - - self.app_handle - .emit("download_error", error.to_string()) - .unwrap(); - - let mut lock = current_status.status.lock().unwrap(); - *lock = DownloadStatus::Error; - self.set_status(DownloadManagerStatus::Error(error)); - - let id = current_status.id.clone(); - self.set_application_status(id, |db_handle, id| { - db_handle.applications.transient_statuses.remove(id); - }); - - self.sender - .send(DownloadManagerSignal::UpdateUIQueue) - .unwrap(); - } - - fn manage_completed_signal(&mut self, id: String) { - info!("Got signal 'Completed'"); - if let Some(interface) = &self.current_download_agent { - if interface.id == id { - info!("Popping consumed data"); - let download_agent = self.remove_and_cleanup_front_download(&id); - let download_agent_lock = download_agent.lock().unwrap(); - - drop(download_agent_lock); - - if let Err(error) = - self.current_download_agent.on_complete(&self.app_handle); - { - self.sender - .send(DownloadManagerSignal::Error( - ApplicationDownloadError::Communication(error), - )) - .unwrap(); - } - } - } - self.sender - .send(DownloadManagerSignal::UpdateUIQueue) - .unwrap(); - self.sender.send(DownloadManagerSignal::Go).unwrap(); - } - - fn manage_stop_signal(&mut self) { - info!("Got signal 'Stop'"); - self.set_status(DownloadManagerStatus::Paused); - if let Some(active_control_flag) = self.active_control_flag.clone() { - active_control_flag.set(DownloadThreadControlFlag::Stop); - } - } - - fn manage_go_signal(&mut self) { - if !(!self.download_agent_registry.is_empty() && !self.download_queue.empty()) { - return; - } - - if self.current_download_agent.is_some() { - info!("skipping go signal due to existing download job"); - return; - } - - info!("current download queue: {:?}", self.download_queue.read()); - let agent_data = self.download_queue.read().front().unwrap().clone(); - info!("starting download for {}", agent_data.id.clone()); - let download_agent = self - .download_agent_registry - .get(&agent_data.id) - .unwrap() - .clone(); - let download_agent_lock = download_agent.lock().unwrap(); - self.current_download_agent = Some(agent_data); - // Cloning option should be okay because it only clones the Arc inside, not the AgentInterfaceData - let agent_data = self.current_download_agent.clone().unwrap(); - - let version_name = download_agent_lock.version().clone(); - - let progress_object = download_agent_lock.progress(); - *self.progress.lock().unwrap() = Some(progress_object); - - let active_control_flag = download_agent_lock.control_flag(); - self.active_control_flag = Some(active_control_flag.clone()); - - let sender = self.sender.clone(); - - drop(download_agent_lock); - - info!("Spawning download"); - let mut download_thread_lock = self.current_download_thread.lock().unwrap(); - *download_thread_lock = Some(spawn(move || { - let mut download_agent_lock = download_agent.lock().unwrap(); - match download_agent_lock.download() { - // Returns once we've exited the download - // (not necessarily completed) - // The download agent will fire the completed event for us - Ok(_) => {} - // If an error occurred while *starting* the download - Err(err) => { - error!("error while managing download: {}", err); - sender.send(DownloadManagerSignal::Error(err)).unwrap(); - } - }; - drop(download_agent_lock); - })); - - // Set status for applications - for queue_application in self.download_queue.read() { - let mut status_handle = queue_application.status.lock().unwrap(); - if queue_application.id == agent_data.id { - *status_handle = DownloadStatus::Downloading; - } else { - *status_handle = DownloadStatus::Queued; - } - drop(status_handle); - } - - // Set flags for download manager - active_control_flag.set(DownloadThreadControlFlag::Go); - self.set_status(DownloadManagerStatus::Downloading); - self.set_application_status(agent_data.id.clone(), |db, id| { - db.applications.transient_statuses.insert( - id.to_string(), - ApplicationTransientStatus::Downloading { version_name }, - ); - }); - - self.sender - .send(DownloadManagerSignal::UpdateUIQueue) - .unwrap(); - } - - fn manage_queue_signal(&mut self, id: String, version: String, target_download_dir: usize) { - info!("Got signal Queue"); - - if let Some(index) = self.download_queue.get_by_id(id.clone()) { - // Should always give us a value - if let Some(download_agent) = self.download_agent_registry.get(&id) { - let download_agent_handle = download_agent.lock().unwrap(); - if download_agent_handle.version() == version { - info!("Application with same version already queued, skipping"); - return; - } - // If it's not the same, we want to cancel the current one, and then add the new one - drop(download_agent_handle); - - self.manage_remove_download_from_queue(id.clone()); - } - } - - let download_agent = Arc::new(Mutex::new(DownloadType::Game.generate( - id.clone(), - version, - target_download_dir, - self.sender.clone(), - ))); - let download_agent_lock = download_agent.lock().unwrap(); - - let agent_status = DownloadStatus::Queued; - let interface_data = DownloadableQueueStandin { - id: id.clone(), - status: Mutex::new(agent_status), - progress: download_agent_lock.progress() - }; - let version_name = download_agent_lock.version().clone(); - - drop(download_agent_lock); - - self.download_agent_registry - .insert(interface_data.id.clone(), download_agent); - self.download_queue.append(interface_data); - - self.set_application_status(id, |db, id| { - db.applications.transient_statuses.insert( - id.to_string(), - ApplicationTransientStatus::Downloading { version_name }, - ); - }); - self.sender - .send(DownloadManagerSignal::UpdateUIQueue) - .unwrap(); - } - - fn stop_and_wait_current_download(&self) { - self.set_status(DownloadManagerStatus::Paused); - if let Some(current_flag) = &self.active_control_flag { - current_flag.set(DownloadThreadControlFlag::Stop); - } - - let mut download_thread_lock = self.current_download_thread.lock().unwrap(); - if let Some(current_download_thread) = download_thread_lock.take() { - current_download_thread.join().unwrap(); - } - drop(download_thread_lock); - } - - fn remove_and_cleanup_front_download(&mut self, id: &String) -> DownloadAgent { - self.download_queue.pop_front(); - let download_agent = self.download_agent_registry.remove(id).unwrap(); - self.cleanup_current_download(); - download_agent - } - - // CAREFUL WITH THIS FUNCTION - // Make sure the download thread is terminated - fn cleanup_current_download(&mut self) { - self.active_control_flag = None; - *self.progress.lock().unwrap() = None; - self.current_download_agent = None; - - let mut download_thread_lock = self.current_download_thread.lock().unwrap(); - *download_thread_lock = None; - drop(download_thread_lock); - } - - fn manage_queue(mut self) -> Result<(), ()> { - loop { - let signal = match self.command_receiver.recv() { - Ok(signal) => signal, - Err(_) => return Err(()), - }; - - match signal { - DownloadManagerSignal::Go => { - self.manage_go_signal(); - } - DownloadManagerSignal::Stop => { - self.manage_stop_signal(); - } - DownloadManagerSignal::Completed(id) => { - self.manage_completed_signal(id); - } - DownloadManagerSignal::Queue(id, version, target_download_dir) => { - self.manage_queue_signal(id, version, target_download_dir); - } - DownloadManagerSignal::Error(e) => { - self.manage_error_signal(e); - } - DownloadManagerSignal::Cancel => { - self.manage_cancel_signal(); - } - 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(); - return Ok(()); - } - DownloadManagerSignal::Remove(id) => { - self.manage_remove_download_from_queue(id); - } - DownloadManagerSignal::Uninstall(id) => { - self.uninstall_application(id); - } - }; - } - } - - - fn manage_remove_download_from_queue(&mut self, id: DownloadableMetadata) { - if let Some(current_download) = &self.current_download_agent { - if current_download.lock().unwrap().metadata() == id { - self.manage_cancel_signal(); - } - } - - let index = self.download_queue.get_by_id(id.clone()); - if let Some(index) = index { - let mut queue_handle = self.download_queue.edit(); - queue_handle.remove(index); - set_application_status(&self.app_handle, id, |db_handle, id| { - db_handle.applications.transient_statuses.remove(id); - }); - drop(queue_handle); - } - - if self.current_download_agent.is_none() { - self.manage_go_signal(); - } - - self.push_ui_queue_update(); - } - - fn manage_go_signal(&mut self) { - if !(!self.download_agent_registry.is_empty() && !self.download_queue.empty()) { - return; - } - - if self.current_download_agent.is_some() { - info!("skipping go signal due to existing download job"); - return; - } - - info!("current download queue: {:?}", self.download_queue.read()); - let agent_data = self.download_queue.read().front().unwrap().clone(); - info!("starting download for {}", agent_data.id.clone()); - let download_agent = self - .download_agent_registry - .get(&agent_data.id) - .unwrap() - .clone(); - let download_agent_lock = download_agent.lock().unwrap(); - self.current_download_agent = Some(agent_data); - // Cloning option should be okay because it only clones the Arc inside, not the AgentInterfaceData - let agent_data = self.current_download_agent.clone().unwrap(); - - let version_name = download_agent_lock.version().clone(); - - let progress_object = download_agent_lock.progress(); - *self.progress.lock().unwrap() = Some(progress_object); - - let active_control_flag = download_agent_lock.control_flag(); - self.active_control_flag = Some(active_control_flag.clone()); - - let sender = self.sender.clone(); - - drop(download_agent_lock); - - info!("Spawning download"); - let mut download_thread_lock = self.current_download_thread.lock().unwrap(); - *download_thread_lock = Some(spawn(move || { - let mut download_agent_lock = download_agent.lock().unwrap(); - match download_agent_lock.download() { - // Returns once we've exited the download - // (not necessarily completed) - // The download agent will fire the completed event for us - Ok(_) => {} - // If an error occurred while *starting* the download - Err(err) => { - error!("error while managing download: {}", err); - sender.send(DownloadManagerSignal::Error(err)).unwrap(); - } - }; - drop(download_agent_lock); - })); - - // Set status for applications - for queue_application in self.download_queue.read() { - let mut status_handle = queue_application.status.lock().unwrap(); - if queue_application.id == agent_data.id { - *status_handle = DownloadStatus::Downloading; - } else { - *status_handle = DownloadStatus::Queued; - } - drop(status_handle); - } - - // Set flags for download manager - active_control_flag.set(DownloadThreadControlFlag::Go); - self.set_status(DownloadManagerStatus::Downloading); - self.set_application_status(agent_data.id.clone(), |db, id| { - db.applications.transient_statuses.insert( - id.to_string(), - ApplicationTransientStatus::Downloading { version_name }, - ); - }); - - self.sender - .send(DownloadManagerSignal::UpdateUIQueue) - .unwrap(); - } -} -*/ +} \ No newline at end of file diff --git a/src-tauri/src/downloads/download_agent.rs b/src-tauri/src/games/downloads/download_agent.rs similarity index 98% rename from src-tauri/src/downloads/download_agent.rs rename to src-tauri/src/games/downloads/download_agent.rs index b2917e5..c003863 100644 --- a/src-tauri/src/downloads/download_agent.rs +++ b/src-tauri/src/games/downloads/download_agent.rs @@ -6,8 +6,8 @@ use crate::download_manager::download_thread_control_flag::{DownloadThreadContro use crate::download_manager::downloadable::Downloadable; use crate::download_manager::downloadable_metadata::{DownloadType, DownloadableMetadata}; use crate::download_manager::progress_object::{ProgressHandle, ProgressObject}; -use crate::downloads::manifest::{DropDownloadContext, DropManifest}; -use crate::library::{on_game_complete, push_game_update}; +use crate::games::downloads::manifest::{DropDownloadContext, DropManifest}; +use crate::games::library::{on_game_complete, push_game_update}; use crate::remote::RemoteAccessError; use crate::DB; use log::{debug, error, info}; diff --git a/src-tauri/src/downloads/download_commands.rs b/src-tauri/src/games/downloads/download_commands.rs similarity index 100% rename from src-tauri/src/downloads/download_commands.rs rename to src-tauri/src/games/downloads/download_commands.rs diff --git a/src-tauri/src/downloads/download_logic.rs b/src-tauri/src/games/downloads/download_logic.rs similarity index 98% rename from src-tauri/src/downloads/download_logic.rs rename to src-tauri/src/games/downloads/download_logic.rs index de0f615..2c942c2 100644 --- a/src-tauri/src/downloads/download_logic.rs +++ b/src-tauri/src/games/downloads/download_logic.rs @@ -3,7 +3,7 @@ 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; +use crate::games::downloads::manifest::DropDownloadContext; use crate::remote::RemoteAccessError; use crate::DB; use http::StatusCode; diff --git a/src-tauri/src/downloads/manifest.rs b/src-tauri/src/games/downloads/manifest.rs similarity index 100% rename from src-tauri/src/downloads/manifest.rs rename to src-tauri/src/games/downloads/manifest.rs diff --git a/src-tauri/src/downloads/mod.rs b/src-tauri/src/games/downloads/mod.rs similarity index 80% rename from src-tauri/src/downloads/mod.rs rename to src-tauri/src/games/downloads/mod.rs index 8709ca6..ba0fac2 100644 --- a/src-tauri/src/downloads/mod.rs +++ b/src-tauri/src/games/downloads/mod.rs @@ -2,4 +2,4 @@ pub mod download_agent; pub mod download_commands; mod download_logic; mod manifest; -mod stored_manifest; +mod stored_manifest; \ No newline at end of file diff --git a/src-tauri/src/downloads/stored_manifest.rs b/src-tauri/src/games/downloads/stored_manifest.rs similarity index 100% rename from src-tauri/src/downloads/stored_manifest.rs rename to src-tauri/src/games/downloads/stored_manifest.rs diff --git a/src-tauri/src/library.rs b/src-tauri/src/games/library.rs similarity index 98% rename from src-tauri/src/library.rs rename to src-tauri/src/games/library.rs index c702ead..2ddd573 100644 --- a/src-tauri/src/library.rs +++ b/src-tauri/src/games/library.rs @@ -14,16 +14,13 @@ use crate::download_manager::download_manager::DownloadStatus; use crate::download_manager::downloadable_metadata::DownloadableMetadata; use crate::process::process_manager::Platform; use crate::remote::RemoteAccessError; -use crate::state::{GameStatusManager, GameStatusWithTransient}; -use crate::remote::{DropServerError, RemoteAccessError}; -use crate::state::{GameStatusManager, GameStatusWithTransient}; +use crate::games::state::{GameStatusManager, GameStatusWithTransient}; use crate::{auth::generate_authorization_header, AppState, DB}; #[derive(serde::Serialize)] pub struct FetchGameStruct { game: Game, status: GameStatusWithTransient, - status: GameStatusWithTransient, } #[derive(Serialize, Deserialize, Clone)] diff --git a/src-tauri/src/games/mod.rs b/src-tauri/src/games/mod.rs new file mode 100644 index 0000000..e49a4ef --- /dev/null +++ b/src-tauri/src/games/mod.rs @@ -0,0 +1,3 @@ +pub mod downloads; +pub mod library; +pub mod state; \ No newline at end of file diff --git a/src-tauri/src/state.rs b/src-tauri/src/games/state.rs similarity index 100% rename from src-tauri/src/state.rs rename to src-tauri/src/games/state.rs diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 171f171..ff9eb76 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,14 +1,12 @@ mod auth; mod db; -mod downloads; -mod library; +mod games; mod autostart; mod cleanup; mod debug; mod process; mod remote; -mod state; mod tools; pub mod download_manager; #[cfg(test)] @@ -27,12 +25,10 @@ use db::{ }; use download_manager::download_manager::DownloadManager; use download_manager::download_manager_builder::DownloadManagerBuilder; -use download_manager::downloadable_metadata::DownloadableMetadata; -use debug::fetch_system_data; -use downloads::download_commands::*; +use games::downloads::download_commands::{cancel_game, download_game, move_game_in_queue, pause_game_downloads, resume_game_downloads}; use http::Response; use http::{header::*, response::Builder as ResponseBuilder}; -use library::{ +use games::library::{ fetch_game, fetch_game_status, fetch_game_verion_options, fetch_library, uninstall_game, Game }; use log::{debug, info, warn, LevelFilter}; diff --git a/src-tauri/src/process/process_manager.rs b/src-tauri/src/process/process_manager.rs index 8ad4bbd..c376037 100644 --- a/src-tauri/src/process/process_manager.rs +++ b/src-tauri/src/process/process_manager.rs @@ -15,7 +15,7 @@ use tauri::{AppHandle, Manager}; use umu_wrapper_lib::command_builder::UmuCommandBuilder; use crate::{ - db::{GameDownloadStatus, ApplicationTransientStatus, DATA_ROOT_DIR}, download_manager::{downloadable::Downloadable, downloadable_metadata::DownloadableMetadata}, library::push_game_update, state::GameStatusManager, AppState, DB + db::{GameDownloadStatus, ApplicationTransientStatus, DATA_ROOT_DIR}, download_manager::{downloadable::Downloadable, downloadable_metadata::DownloadableMetadata}, games::library::push_game_update, games::state::GameStatusManager, AppState, DB }; pub struct ProcessManager<'a> {