diff --git a/desktop/app.vue b/desktop/app.vue index 4218fe2d..6ae77a58 100644 --- a/desktop/app.vue +++ b/desktop/app.vue @@ -6,8 +6,7 @@ diff --git a/desktop/pages/library/[id]/index.vue b/desktop/pages/library/[id]/index.vue index 94275bad..6ae50ac8 100644 --- a/desktop/pages/library/[id]/index.vue +++ b/desktop/pages/library/[id]/index.vue @@ -18,7 +18,7 @@
- +
@@ -27,15 +27,22 @@ diff --git a/desktop/src-tauri/src/db.rs b/desktop/src-tauri/src/db.rs index 66d08b5b..b2054059 100644 --- a/desktop/src-tauri/src/db.rs +++ b/desktop/src-tauri/src/db.rs @@ -25,6 +25,7 @@ pub struct DatabaseAuth { #[derive(Serialize, Clone, Deserialize)] pub enum DatabaseGameStatus { Remote, + Queued, Downloading, Installed, Updating, diff --git a/desktop/src-tauri/src/downloads/download_manager_builder.rs b/desktop/src-tauri/src/downloads/download_manager_builder.rs index 656d299d..5c4a723e 100644 --- a/desktop/src-tauri/src/downloads/download_manager_builder.rs +++ b/desktop/src-tauri/src/downloads/download_manager_builder.rs @@ -8,6 +8,9 @@ use std::{ }; use log::{error, info, warn}; +use tauri::{AppHandle, Emitter}; + +use crate::{db::DatabaseGameStatus, library::GameUpdateEvent, DB}; use super::{ download_agent::{GameDownloadAgent, GameDownloadError}, @@ -64,13 +67,14 @@ pub struct DownloadManagerBuilder { sender: Sender, progress: Arc>>, status: Arc>, + app_handle: AppHandle, current_game_interface: Option>, // Should be the only game download agent in the map with the "Go" flag active_control_flag: Option, } impl DownloadManagerBuilder { - pub fn build() -> DownloadManager { + pub fn build(app_handle: AppHandle) -> DownloadManager { let queue = Queue::new(); let (command_sender, command_receiver) = channel(); let active_progress = Arc::new(Mutex::new(None)); @@ -85,6 +89,7 @@ impl DownloadManagerBuilder { status: status.clone(), sender: command_sender.clone(), progress: active_progress.clone(), + app_handle, }; let terminator = spawn(|| manager.manage_queue()); @@ -92,6 +97,23 @@ impl DownloadManagerBuilder { DownloadManager::new(terminator, queue, active_progress, command_sender) } + fn set_game_status(&self, id: String, status: DatabaseGameStatus) { + let mut db_handle = DB.borrow_data_mut().unwrap(); + db_handle + .games + .games_statuses + .insert(id.clone(), status.clone()); + self.app_handle + .emit( + &format!("update_game/{}", id), + GameUpdateEvent { + game_id: id, + status: status, + }, + ) + .unwrap(); + } + fn manage_queue(mut self) -> Result<(), ()> { loop { let signal = match self.command_receiver.recv() { @@ -145,6 +167,8 @@ impl DownloadManagerBuilder { self.download_agent_registry.remove(&game_id); self.active_control_flag = None; *self.progress.lock().unwrap() = None; + + self.set_game_status(game_id, DatabaseGameStatus::Installed); } } self.sender.send(DownloadManagerSignal::Go).unwrap(); @@ -160,54 +184,61 @@ impl DownloadManagerBuilder { )); let agent_status = GameDownloadStatus::Uninitialised; let interface_data = AgentInterfaceData { - id, + id: id.clone(), status: Mutex::new(agent_status), }; self.download_agent_registry .insert(interface_data.id.clone(), download_agent); self.download_queue.append(interface_data); + + self.set_game_status(id, DatabaseGameStatus::Queued); } fn manage_go_signal(&mut self) { info!("Got signal 'Go'"); - if !self.download_agent_registry.is_empty() && !self.download_queue.empty() { - info!("Starting download agent"); - let agent_data = self.download_queue.read().front().unwrap().clone(); - let download_agent = self - .download_agent_registry - .get(&agent_data.id) - .unwrap() - .clone(); - self.current_game_interface = Some(agent_data); - let progress_object = download_agent.progress.clone(); - *self.progress.lock().unwrap() = Some(progress_object); - - let active_control_flag = download_agent.control_flag.clone(); - self.active_control_flag = Some(active_control_flag.clone()); - - let sender = self.sender.clone(); - - info!("Spawning download"); - spawn(move || { - match download_agent.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(); - } - }; - }); - - active_control_flag.set(DownloadThreadControlFlag::Go); - self.set_status(DownloadManagerStatus::Downloading); - } else { - info!("Nothing was set"); + if !(!self.download_agent_registry.is_empty() && !self.download_queue.empty()) { + return; } + + info!("Starting download agent"); + let agent_data = self.download_queue.read().front().unwrap().clone(); + let download_agent = self + .download_agent_registry + .get(&agent_data.id) + .unwrap() + .clone(); + self.current_game_interface = Some(agent_data); + + let progress_object = download_agent.progress.clone(); + *self.progress.lock().unwrap() = Some(progress_object); + + let active_control_flag = download_agent.control_flag.clone(); + self.active_control_flag = Some(active_control_flag.clone()); + + let sender = self.sender.clone(); + + info!("Spawning download"); + spawn(move || { + match download_agent.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(); + } + }; + }); + + active_control_flag.set(DownloadThreadControlFlag::Go); + self.set_status(DownloadManagerStatus::Downloading); + self.set_game_status( + self.current_game_interface.as_ref().unwrap().id.clone(), + DatabaseGameStatus::Downloading, + ); } fn manage_error_signal(&self, error: GameDownloadError) { let current_status = self.current_game_interface.clone().unwrap(); diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index 8d1dbd2b..a245d3dd 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -28,6 +28,7 @@ use std::{ collections::HashMap, sync::{LazyLock, Mutex}, }; +use tauri::{AppHandle, Manager}; use tauri_plugin_deep_link::DeepLinkExt; #[derive(Clone, Copy, Serialize)] @@ -69,12 +70,12 @@ fn fetch_state(state: tauri::State<'_, Mutex>) -> Result AppState { +fn setup(handle: AppHandle) -> AppState { debug!("Starting env"); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); let games = HashMap::new(); - let download_manager = Arc::new(DownloadManagerBuilder::build()); + let download_manager = Arc::new(DownloadManagerBuilder::build(handle)); debug!("Checking if database is set up"); let is_set_up = DB.database_is_set_up(); @@ -102,9 +103,6 @@ pub static DB: LazyLock = LazyLock::new(DatabaseInterface::se #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { - let state = setup(); - info!("initialized drop client"); - let mut builder = tauri::Builder::default().plugin(tauri_plugin_dialog::init()); #[cfg(desktop)] @@ -117,7 +115,6 @@ pub fn run() { builder .plugin(tauri_plugin_deep_link::init()) - .manage(Mutex::new(state)) .invoke_handler(tauri::generate_handler![ // DB fetch_state, @@ -144,6 +141,11 @@ pub fn run() { .plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_dialog::init()) .setup(|app| { + let handle = app.handle().clone(); + let state = setup(handle); + info!("initialized drop client"); + app.manage(Mutex::new(state)); + #[cfg(any(target_os = "linux", all(debug_assertions, windows)))] { use tauri_plugin_deep_link::DeepLinkExt; diff --git a/desktop/src-tauri/src/library.rs b/desktop/src-tauri/src/library.rs index 64372b8c..fe792a30 100644 --- a/desktop/src-tauri/src/library.rs +++ b/desktop/src-tauri/src/library.rs @@ -33,6 +33,11 @@ pub struct Game { m_cover_id: String, m_image_library: Vec, } +#[derive(serde::Serialize, Clone)] +pub struct GameUpdateEvent { + pub game_id: String, + pub status: DatabaseGameStatus, +} fn fetch_library_logic(app: AppHandle) -> Result { let base_url = DB.fetch_base_url(); diff --git a/desktop/types.d.ts b/desktop/types.ts similarity index 97% rename from desktop/types.d.ts rename to desktop/types.ts index b63d9043..9b91f485 100644 --- a/desktop/types.d.ts +++ b/desktop/types.ts @@ -27,6 +27,7 @@ export enum AppStatus { export enum GameStatus { Remote = "Remote", + Queued = "Queued", Downloading = "Downloading", Installed = "Installed", Updating = "Updating",