diff --git a/src-tauri/src/download_manager/download_manager_builder.rs b/src-tauri/src/download_manager/download_manager_builder.rs index a921ea2..1fb5afc 100644 --- a/src-tauri/src/download_manager/download_manager_builder.rs +++ b/src-tauri/src/download_manager/download_manager_builder.rs @@ -165,6 +165,56 @@ impl DownloadManagerBuilder { self.sender.send(DownloadManagerSignal::UpdateUIQueue).unwrap(); } + + fn manage_go_signal(&mut self) { + info!("Got signal Go"); + if !(self.download_agent_registry.is_empty()) { return; } + + if self.current_download_agent.is_some() { return; } + + info!("Current download queue: {:?}", self.download_queue.read()); + + // Should always be Some if the above two statements keep going + let agent_data = self.download_queue.read().front().unwrap().clone(); + + info!("Starting download for {:?}", agent_data); + + let download_agent = self + .download_agent_registry + .get(&agent_data) + .unwrap() + .clone(); + + self.active_control_flag = Some(download_agent.control_flag()); + self.current_download_agent = Some(download_agent.clone()); + + let sender = self.sender.clone(); + + let mut download_thread_lock = self.current_download_thread.lock().unwrap(); + let app_handle = self.app_handle.clone(); + + *download_thread_lock = Some(spawn(move || { + match download_agent.download() { + // Ok(true) is for completed and exited properly + Ok(true) => { + download_agent.on_complete(&app_handle); + }, + // Ok(false) is for incomplete but exited properly + Ok(false) => { + download_agent.on_incomplete(&app_handle); + }, + Err(e) => { + download_agent.on_error(&app_handle); + error!("error while managing download: {}", e); + sender.send(DownloadManagerSignal::Error(e)).unwrap(); + }, + } + })); + + let active_control_flag = self.active_control_flag.clone().unwrap(); + active_control_flag.set(DownloadThreadControlFlag::Go); + + } } /* // Refactored to consolidate this type. It's a monster. @@ -172,56 +222,6 @@ pub type DownloadAgent = Arc>>; impl DownloadManagerBuilder { - 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 manage_go_signal(&mut self) { if !(!self.download_agent_registry.is_empty() && !self.download_queue.empty()) { return; @@ -301,6 +301,57 @@ impl DownloadManagerBuilder { .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 push_ui_stats_update(&self, kbs: usize, time: usize) { let event_data = StatsUpdateEvent { speed: kbs, time }; diff --git a/src-tauri/src/download_manager/downloadable.rs b/src-tauri/src/download_manager/downloadable.rs index 693652b..4c9c5bf 100644 --- a/src-tauri/src/download_manager/downloadable.rs +++ b/src-tauri/src/download_manager/downloadable.rs @@ -7,11 +7,12 @@ use super::{ }; pub trait Downloadable: Send + Sync { - fn download(&mut self) -> Result<(), ApplicationDownloadError>; + fn download(&self) -> Result; fn progress(&self) -> Arc; fn control_flag(&self) -> DownloadThreadControl; fn metadata(&self) -> Arc; fn on_initialised(&self, app_handle: &AppHandle); fn on_error(&self, app_handle: &AppHandle); fn on_complete(&self, app_handle: &AppHandle); + fn on_incomplete(&self, app_handle: &AppHandle); } diff --git a/src-tauri/src/downloads/download_agent.rs b/src-tauri/src/downloads/download_agent.rs index f91372d..2e46b8b 100644 --- a/src-tauri/src/downloads/download_agent.rs +++ b/src-tauri/src/downloads/download_agent.rs @@ -28,8 +28,8 @@ pub struct GameDownloadAgent { pub id: String, pub version: String, pub control_flag: DownloadThreadControl, - contexts: Vec, - completed_contexts: VecDeque, + contexts: Mutex>, + completed_contexts: Mutex>, pub manifest: Mutex>, pub progress: Arc, sender: Sender, @@ -63,8 +63,8 @@ impl GameDownloadAgent { version, control_flag, manifest: Mutex::new(None), - contexts: Vec::new(), - completed_contexts: VecDeque::new(), + contexts: Mutex::new(Vec::new()), + completed_contexts: Mutex::new(VecDeque::new()), progress: Arc::new(ProgressObject::new(0, 0, sender.clone())), sender, stored_manifest, @@ -72,7 +72,7 @@ impl GameDownloadAgent { } // Blocking - pub fn setup_download(&mut self) -> Result<(), ApplicationDownloadError> { + pub fn setup_download(&self) -> Result<(), ApplicationDownloadError> { self.ensure_manifest_exists()?; info!("Ensured manifest exists"); @@ -85,7 +85,7 @@ impl GameDownloadAgent { } // Blocking - pub fn download(&mut self) -> Result<(), ApplicationDownloadError> { + pub fn download(&self) -> Result<(), ApplicationDownloadError> { self.setup_download()?; self.set_progress_object_params(); let timer = Instant::now(); @@ -153,9 +153,11 @@ impl GameDownloadAgent { return; } - let length = self.contexts.len(); + let contexts = self.contexts.lock().unwrap(); - let chunk_count = self.contexts.iter().map(|chunk| chunk.length).sum(); + let length = contexts.len(); + + let chunk_count = contexts.iter().map(|chunk| chunk.length).sum(); debug!("Setting ProgressObject max to {}", chunk_count); self.progress.set_max(chunk_count); @@ -165,8 +167,8 @@ impl GameDownloadAgent { self.progress.set_time_now(); } - pub fn ensure_contexts(&mut self) -> Result<(), ApplicationDownloadError> { - if !self.contexts.is_empty() { + pub fn ensure_contexts(&self) -> Result<(), ApplicationDownloadError> { + if !self.contexts.lock().unwrap().is_empty() { return Ok(()); } @@ -174,7 +176,7 @@ impl GameDownloadAgent { Ok(()) } - pub fn generate_contexts(&mut self) -> Result<(), ApplicationDownloadError> { + pub fn generate_contexts(&self) -> Result<(), ApplicationDownloadError> { let manifest = self.manifest.lock().unwrap().clone().unwrap(); let game_id = self.id.clone(); @@ -182,9 +184,13 @@ impl GameDownloadAgent { let base_path = Path::new(&self.stored_manifest.base_path); create_dir_all(base_path).unwrap(); - self.completed_contexts.clear(); - self.completed_contexts - .extend(self.stored_manifest.get_completed_contexts()); + + { + let mut completed_contexts_lock = self.completed_contexts.lock().unwrap(); + completed_contexts_lock.clear(); + completed_contexts_lock + .extend(self.stored_manifest.get_completed_contexts()); + } for (raw_path, chunk) in manifest { let path = base_path.join(Path::new(&raw_path)); @@ -215,12 +221,12 @@ impl GameDownloadAgent { let _ = fallocate(file, FallocateFlags::empty(), 0, running_offset); } } - self.contexts = contexts; + *self.contexts.lock().unwrap() = contexts; Ok(()) } - pub fn run(&mut self) -> Result<(), ()> { + pub fn run(&self) -> Result<(), ()> { info!("downloading game: {}", self.id); const DOWNLOAD_MAX_THREADS: usize = 1; @@ -233,13 +239,13 @@ impl GameDownloadAgent { let completed_indexes_loop_arc = completed_indexes.clone(); pool.scope(|scope| { - for (index, context) in self.contexts.iter().enumerate() { + for (index, context) in self.contexts.lock().unwrap().iter().enumerate() { let completed_indexes = completed_indexes_loop_arc.clone(); let progress = self.progress.get(index); // Clone arcs let progress_handle = ProgressHandle::new(progress, self.progress.clone()); // If we've done this one already, skip it - if self.completed_contexts.contains(&index) { + if self.completed_contexts.lock().unwrap().contains(&index) { progress_handle.add(context.length); continue; } @@ -268,18 +274,19 @@ impl GameDownloadAgent { let newly_completed = completed_indexes.to_owned(); let completed_lock_len = { + let mut completed_contexts_lock = self.completed_contexts.lock().unwrap(); for (item, _) in newly_completed.iter() { - self.completed_contexts.push_front(item); + completed_contexts_lock.push_front(item); } - self.completed_contexts.len() + completed_contexts_lock.len() }; // If we're not out of contexts, we're not done, so we don't fire completed if completed_lock_len != self.contexts.len() { info!("da for {} exited without completing", self.id.clone()); self.stored_manifest - .set_completed_contexts(&self.completed_contexts.clone().into()); + .set_completed_contexts(&self.completed_contexts.lock().unwrap().clone().into()); info!("Setting completed contexts"); self.stored_manifest.write(); info!("Wrote completed contexts"); @@ -297,7 +304,7 @@ impl GameDownloadAgent { impl Downloadable for GameDownloadAgent { - fn download(&mut self) -> Result<(), ApplicationDownloadError> { + fn download(&self) -> Result<(), ApplicationDownloadError> { self.download() } @@ -320,4 +327,8 @@ impl Downloadable for GameDownloadAgent { fn on_complete(&self, app_handle: &AppHandle>) { on_game_complete(id, version, install_dir, app_handle) } + + fn on_initialised(&self, app_handle: &tauri::AppHandle) { + todo!() + } } \ No newline at end of file