From 1ab61c86b1acd2dc3d3af88d1770538fd236f513 Mon Sep 17 00:00:00 2001 From: quexeky Date: Mon, 28 Oct 2024 19:23:41 +1100 Subject: [PATCH] I think that download queuing is working --- pages/store/index.vue | 27 ++++--- src-tauri/src/downloads/download_agent.rs | 32 ++------- src-tauri/src/downloads/download_commands.rs | 76 ++++++++++++++++++++ src-tauri/src/downloads/download_logic.rs | 23 ++---- src-tauri/src/downloads/mod.rs | 3 +- src-tauri/src/lib.rs | 12 ++-- 6 files changed, 117 insertions(+), 56 deletions(-) create mode 100644 src-tauri/src/downloads/download_commands.rs diff --git a/pages/store/index.vue b/pages/store/index.vue index bb2bedb..8ee2ae7 100644 --- a/pages/store/index.vue +++ b/pages/store/index.vue @@ -1,17 +1,17 @@ diff --git a/src-tauri/src/downloads/download_agent.rs b/src-tauri/src/downloads/download_agent.rs index 487f388..28e93b5 100644 --- a/src-tauri/src/downloads/download_agent.rs +++ b/src-tauri/src/downloads/download_agent.rs @@ -14,8 +14,8 @@ use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Mutex}; pub struct GameDownloadAgent { - id: String, - version: String, + pub id: String, + pub version: String, state: Mutex, contexts: Mutex>, progress: ProgressChecker, @@ -126,6 +126,10 @@ impl GameDownloadAgent { let mut lock = self.state.lock().unwrap(); *lock = state; } + pub fn get_state(&self) -> GameDownloadState { + let lock = self.state.lock().unwrap(); + lock.clone() + } pub fn generate_job_contexts( &self, @@ -174,27 +178,3 @@ impl GameDownloadAgent { } } -#[tauri::command] -pub async fn start_game_download( - game_id: String, - game_version: String, - max_threads: usize, - state: tauri::State<'_, Mutex>, -) -> Result<(), GameDownloadError> { - info!("Triggered Game Download"); - - let download_agent = GameDownloadAgent::new(game_id.clone(), game_version.clone()); - - download_agent.ensure_manifest_exists().await?; - - let local_manifest = { - let manifest = download_agent.manifest.lock().unwrap(); - (*manifest).clone().unwrap() - }; - - download_agent.generate_job_contexts(&local_manifest, game_version.clone(), game_id).unwrap(); - - download_agent.begin_download(max_threads)?; - - Ok(()) -} diff --git a/src-tauri/src/downloads/download_commands.rs b/src-tauri/src/downloads/download_commands.rs new file mode 100644 index 0000000..05a17ef --- /dev/null +++ b/src-tauri/src/downloads/download_commands.rs @@ -0,0 +1,76 @@ +use std::sync::{Arc, Mutex}; + +use log::info; + +use crate::{downloads::download_agent::GameDownloadAgent, AppState}; + +use super::download_agent::{GameDownloadError, GameDownloadState}; + +#[tauri::command] +pub async fn queue_game_download( + game_id: String, + game_version: String, + state: tauri::State<'_, Mutex>, +) -> Result<(), GameDownloadError> { + info!("Queuing Game Download"); + let download_agent = Arc::new(GameDownloadAgent::new(game_id.clone(), game_version.clone())); + download_agent.queue().await?; + + let mut queue = state.lock().unwrap(); + queue.game_downloads.insert(game_id, download_agent); + Ok(()) +} + +#[tauri::command] +pub async fn start_game_downloads( + max_threads: usize, + state: tauri::State<'_, Mutex>, +) -> Result<(), GameDownloadError> { + info!("Downloading Games"); + loop { + let mut current_id = String::new(); + let mut download_agent = None; + { + let lock = state.lock().unwrap(); + for (id, agent) in &lock.game_downloads { + if agent.get_state() == GameDownloadState::Queued { + download_agent = Some(agent.clone()); + current_id = id.clone(); + info!("Got queued game to download"); + break; + } + } + if download_agent.is_none() { + info!("No more games left to download"); + return Ok(()) + } + }; + info!("Downloading game"); + start_game_download(max_threads, download_agent.unwrap()).await?; + { + let mut lock = state.lock().unwrap(); + lock.game_downloads.remove_entry(¤t_id); + } + } +} + +pub async fn start_game_download( + max_threads: usize, + download_agent: Arc +) -> Result<(), GameDownloadError> { + info!("Triggered Game Download"); + + + download_agent.ensure_manifest_exists().await?; + + let local_manifest = { + let manifest = download_agent.manifest.lock().unwrap(); + (*manifest).clone().unwrap() + }; + + download_agent.generate_job_contexts(&local_manifest, download_agent.version.clone(), download_agent.id.clone()).unwrap(); + + download_agent.begin_download(max_threads)?; + + Ok(()) +} \ No newline at end of file diff --git a/src-tauri/src/downloads/download_logic.rs b/src-tauri/src/downloads/download_logic.rs index b364959..170ee71 100644 --- a/src-tauri/src/downloads/download_logic.rs +++ b/src-tauri/src/downloads/download_logic.rs @@ -5,33 +5,28 @@ use crate::DB; use gxhash::{gxhash128, GxHasher}; use log::info; use md5::{Context, Digest}; -use std::{fs::{File, OpenOptions}, hash::Hasher, io::{Seek, SeekFrom, Write}, path::PathBuf}; +use std::{fs::{File, OpenOptions}, hash::Hasher, io::{self, Seek, SeekFrom, Write}, path::PathBuf}; use urlencoding::encode; pub struct FileWriter { file: File, hasher: Context, - data: Vec } impl FileWriter { fn new(path: PathBuf) -> Self { Self { file: OpenOptions::new().write(true).open(path).unwrap(), hasher: Context::new(), - data: Vec::new() } } - fn finish(mut self) -> Digest { - self.flush(); - let res = self.hasher.compute(); - info!("Final calculated value hash: {:?}", hex::encode(res.0)); - res + fn finish(mut self) -> io::Result { + self.flush().unwrap(); + Ok(self.hasher.compute()) } } impl Write for FileWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.hasher.write(buf); - self.data.extend_from_slice(buf); + self.hasher.write_all(buf).unwrap(); self.file.write(buf) } @@ -82,13 +77,9 @@ pub fn download_game_chunk(ctx: DropDownloadContext) { response.copy_to(&mut file).unwrap(); - let res = hex::encode(file.finish().0); - if res == ctx.checksum { - info!("Matched Checksum {}", res); - } - else { + let res = hex::encode(file.finish().unwrap().0); + if res != ctx.checksum { info!("Checksum failed. Original: {}, Calculated: {} for {}", ctx.checksum, res, ctx.file_name); - //info!("Other Checksum: {}", hex::encode(checksum)); } // stream.flush().unwrap(); diff --git a/src-tauri/src/downloads/mod.rs b/src-tauri/src/downloads/mod.rs index d7fbe63..bfbc2bc 100644 --- a/src-tauri/src/downloads/mod.rs +++ b/src-tauri/src/downloads/mod.rs @@ -1,4 +1,5 @@ mod manifest; pub mod progress; pub mod download_agent; -mod download_logic; \ No newline at end of file +mod download_logic; +pub mod download_commands; \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5bed827..da0413b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -10,6 +10,7 @@ mod tests; use auth::{auth_initiate, generate_authorization_header, recieve_handshake}; use db::{DatabaseInterface, DATA_ROOT_DIR}; +use downloads::download_commands::{queue_game_download, start_game_downloads}; use env_logger::Env; use http::{header::*, response::Builder as ResponseBuilder}; use library::{fetch_game, fetch_library, Game}; @@ -22,7 +23,7 @@ use std::{ use std::sync::Arc; use tauri_plugin_deep_link::DeepLinkExt; use crate::db::DatabaseImpls; -use crate::downloads::download_agent::{start_game_download, GameDownloadAgent}; +use crate::downloads::download_agent::{GameDownloadAgent}; #[derive(Clone, Copy, Serialize)] pub enum AppStatus { @@ -49,7 +50,7 @@ pub struct AppState { games: HashMap, #[serde(skip_serializing)] - game_downloads: Vec> + game_downloads: HashMap> } #[tauri::command] @@ -69,7 +70,7 @@ fn setup() -> AppState { status: AppStatus::NotConfigured, user: None, games: HashMap::new(), - game_downloads: vec![], + game_downloads: HashMap::new(), }; } @@ -78,7 +79,7 @@ fn setup() -> AppState { status: auth_result.0, user: auth_result.1, games: HashMap::new(), - game_downloads: vec![], + game_downloads: HashMap::new(), } } @@ -113,7 +114,8 @@ pub fn run() { fetch_library, fetch_game, // Downloads - start_game_download + queue_game_download, + start_game_downloads ]) .plugin(tauri_plugin_shell::init()) .setup(|app| {