chore(downloads): partial download manager

This commit is contained in:
DecDuck
2024-11-12 09:06:28 +11:00
parent 5e3d26b3ca
commit 3dbf5ab573
5 changed files with 66 additions and 11 deletions

View File

@ -4,11 +4,13 @@ use crate::downloads::manifest::{DropDownloadContext, DropManifest};
use crate::remote::RemoteAccessError; use crate::remote::RemoteAccessError;
use crate::DB; use crate::DB;
use log::info; use log::info;
use rayon::ThreadPoolBuilder; use rayon::{spawn, ThreadPool, ThreadPoolBuilder};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::fs::{create_dir_all, File}; use std::fs::{create_dir_all, File};
use std::path::Path; use std::path::Path;
use std::sync::Mutex; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::thread::Thread;
use urlencoding::encode; use urlencoding::encode;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
@ -207,6 +209,7 @@ impl GameDownloadAgent {
.build() .build()
.unwrap(); .unwrap();
pool.scope(move |scope| { pool.scope(move |scope| {
let contexts = self.contexts.lock().unwrap(); let contexts = self.contexts.lock().unwrap();
@ -223,6 +226,6 @@ impl GameDownloadAgent {
download_game_chunk(context, control_flag, progress).unwrap(); download_game_chunk(context, control_flag, progress).unwrap();
}); });
} }
}) });
} }
} }

View File

@ -11,6 +11,7 @@ pub fn download_game(
game_version: String, game_version: String,
state: tauri::State<'_, Mutex<AppState>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<(), String> { ) -> Result<(), String> {
/*
info!("beginning game download..."); info!("beginning game download...");
let mut download_agent = GameDownloadAgent::new(game_id.clone(), game_version.clone(), 0); let mut download_agent = GameDownloadAgent::new(game_id.clone(), game_version.clone(), 0);
@ -19,7 +20,7 @@ pub fn download_game(
let mut lock: std::sync::MutexGuard<'_, AppState> = state.lock().unwrap(); let mut lock: std::sync::MutexGuard<'_, AppState> = state.lock().unwrap();
let download_agent_ref = Arc::new(download_agent); let download_agent_ref = Arc::new(download_agent);
lock.game_downloads lock.download_manager
.insert(game_id, download_agent_ref.clone()); .insert(game_id, download_agent_ref.clone());
// Run it in another thread // Run it in another thread
@ -27,6 +28,7 @@ pub fn download_game(
// Run doesn't require mutable // Run doesn't require mutable
download_agent_ref.clone().run(); download_agent_ref.clone().run();
}); });
*/
Ok(()) Ok(())
} }
@ -36,18 +38,23 @@ pub fn get_game_download_progress(
state: tauri::State<'_, Mutex<AppState>>, state: tauri::State<'_, Mutex<AppState>>,
game_id: String, game_id: String,
) -> Result<f64, String> { ) -> Result<f64, String> {
/*
let download_agent = use_download_agent(state, game_id)?; let download_agent = use_download_agent(state, game_id)?;
let progress = &download_agent.progress; let progress = &download_agent.progress;
Ok(progress.get_progress()) Ok(progress.get_progress())
} */
Ok(0.0)
}
/*
fn use_download_agent( fn use_download_agent(
state: tauri::State<'_, Mutex<AppState>>, state: tauri::State<'_, Mutex<AppState>>,
game_id: String, game_id: String,
) -> Result<Arc<GameDownloadAgent>, String> { ) -> Result<Arc<GameDownloadAgent>, String> {
let lock = state.lock().unwrap(); let lock = state.lock().unwrap();
let download_agent = lock.game_downloads.get(&game_id).ok_or("Invalid game ID")?; let download_agent = lock.download_manager.get(&game_id).ok_or("Invalid game ID")?;
Ok(download_agent.clone()) // Clones the Arc, not the underlying data structure Ok(download_agent.clone()) // Clones the Arc, not the underlying data structure
} }
*/

View File

@ -0,0 +1,40 @@
use std::{
collections::HashMap,
sync::{Arc, Mutex},
thread::JoinHandle,
};
use super::{download_agent::GameDownloadAgent, download_thread_control_flag::DownloadThreadControlFlag};
pub struct DownloadManager {
download_agent_registry: HashMap<String, Arc<Mutex<GameDownloadAgent>>>,
download_queue: Vec<String>,
current_thread: Option<JoinHandle<()>>,
current_game_id: Option<String>, // Should be the only game download agent in the map with the "Go" flag
}
impl DownloadManager {
pub fn new() -> Self {
return Self {
download_agent_registry: HashMap::new(),
download_queue: Vec::new(),
current_thread: None,
current_game_id: None,
};
}
pub fn queue_game(&mut self, game_id: String, version_name: String) {
let existing_da = self.download_agent_registry.get(&game_id);
if let Some(da_mutex) = existing_da {
let da = da_mutex.lock().unwrap();
if da.version == version_name {
return; // We're already queued
}
da.control_flag.set(DownloadThreadControlFlag::Stop);
}
}
}

View File

@ -1,5 +1,6 @@
pub mod download_agent; pub mod download_agent;
pub mod download_commands; pub mod download_commands;
pub mod download_manager;
mod download_logic; mod download_logic;
mod download_thread_control_flag; mod download_thread_control_flag;
mod manifest; mod manifest;

View File

@ -13,6 +13,7 @@ use crate::downloads::download_agent::GameDownloadAgent;
use auth::{auth_initiate, generate_authorization_header, recieve_handshake}; use auth::{auth_initiate, generate_authorization_header, recieve_handshake};
use db::{add_new_download_dir, DatabaseInterface, DATA_ROOT_DIR}; use db::{add_new_download_dir, DatabaseInterface, DATA_ROOT_DIR};
use downloads::download_commands::*; use downloads::download_commands::*;
use downloads::download_manager::DownloadManager;
use env_logger::Env; use env_logger::Env;
use http::{header::*, response::Builder as ResponseBuilder}; use http::{header::*, response::Builder as ResponseBuilder};
use library::{fetch_game, fetch_library, Game}; use library::{fetch_game, fetch_library, Game};
@ -53,7 +54,7 @@ pub struct AppState {
games: HashMap<String, Game>, games: HashMap<String, Game>,
#[serde(skip_serializing)] #[serde(skip_serializing)]
game_downloads: HashMap<String, Arc<GameDownloadAgent>>, download_manager: Arc<DownloadManager>,
} }
#[tauri::command] #[tauri::command]
@ -67,13 +68,16 @@ fn fetch_state(state: tauri::State<'_, Mutex<AppState>>) -> Result<AppState, Str
fn setup() -> AppState { fn setup() -> AppState {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init(); env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let games = HashMap::new();
let download_manager = Arc::new(DownloadManager::new());
let is_set_up = DB.database_is_set_up(); let is_set_up = DB.database_is_set_up();
if !is_set_up { if !is_set_up {
return AppState { return AppState {
status: AppStatus::NotConfigured, status: AppStatus::NotConfigured,
user: None, user: None,
games: HashMap::new(), games,
game_downloads: HashMap::new(), download_manager,
}; };
} }
@ -81,8 +85,8 @@ fn setup() -> AppState {
AppState { AppState {
status: app_status, status: app_status,
user, user,
games: HashMap::new(), games,
game_downloads: HashMap::new(), download_manager,
} }
} }