feat(downloads): reduce scope of download agent

due to a miscommunication, the scope of the download agent has grown too
much. this commit reduces that scopes, and intends for a lot of the
heavy lifting to be done by the soon-to-be-implemented download manager.
This commit is contained in:
DecDuck
2024-11-10 22:25:54 +11:00
parent 4983b25702
commit 6a38ea306b
10 changed files with 352 additions and 511 deletions

View File

@ -1,137 +1,62 @@
use std::{
borrow::Borrow,
sync::{Arc, Mutex},
thread,
};
use log::info;
use rayon::spawn;
use crate::{downloads::download_agent::GameDownloadAgent, AppState};
use super::download_agent::{GameDownloadError, GameDownloadState};
#[tauri::command]
pub async fn queue_game_download(
pub fn download_game(
game_id: String,
game_version: String,
state: tauri::State<'_, Mutex<AppState>>,
) -> 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<AppState>>,
) -> Result<(), GameDownloadError> {
info!("Downloading Games");
let lock = state.lock().unwrap();
let mut game_downloads = lock.game_downloads.clone();
drop(lock);
thread::spawn(move || loop {
let mut current_id = String::new();
let mut download_agent = None;
{
for (id, agent) in &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;
}
};
info!("Downloading game");
{
start_game_download(max_threads, download_agent.unwrap()).unwrap();
game_downloads.remove_entry(&current_id);
}
});
info!("Spawned download");
Ok(())
}
pub fn start_game_download(
max_threads: usize,
download_agent: Arc<GameDownloadAgent>,
) -> Result<(), GameDownloadError> {
info!("Triggered Game Download");
download_agent.ensure_manifest_exists()?;
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).unwrap();
Ok(())
}
#[tauri::command]
pub async fn cancel_specific_game_download(
state: tauri::State<'_, Mutex<AppState>>,
game_id: String,
) -> Result<(), String> {
info!("called stop_specific_game_download");
get_game_download(state, game_id).change_state(GameDownloadState::Cancelled);
info!("beginning game download...");
//TODO: Drop the game download instance
let mut download_agent = GameDownloadAgent::new(game_id.clone(), game_version.clone(), 0);
// Setup download requires mutable
download_agent.setup_download().unwrap();
info!("Stopping callback");
let mut lock: std::sync::MutexGuard<'_, AppState> = state.lock().unwrap();
let download_agent_ref = Arc::new(download_agent);
lock.game_downloads
.insert(game_id, download_agent_ref.clone());
// Run it in another thread
spawn(move || {
// Run doesn't require mutable
download_agent_ref.clone().run();
});
Ok(())
}
#[tauri::command]
pub async fn get_game_download_progress(
pub fn get_game_download_progress(
state: tauri::State<'_, Mutex<AppState>>,
game_id: String,
) -> Result<f64, String> {
let progress = get_game_download(state, game_id)
.progress
.get_progress_percentage();
info!("{}", progress);
Ok(progress)
let da = use_download_agent(state, game_id)?;
let progress = &da.progress;
let current: f64 = progress
.current
.fetch_add(0, std::sync::atomic::Ordering::Relaxed) as f64;
let max = progress.max as f64;
let current_progress = current / max;
Ok(current_progress)
}
#[tauri::command]
pub async fn set_download_state(
fn use_download_agent(
state: tauri::State<'_, Mutex<AppState>>,
game_id: String,
status: GameDownloadState,
) -> Result<(), String> {
info!("Setting game state");
get_game_download(state, game_id).change_state(status);
Ok(())
}
fn get_game_download(
state: tauri::State<'_, Mutex<AppState>>,
game_id: String,
) -> Arc<GameDownloadAgent> {
) -> Result<Arc<GameDownloadAgent>, String> {
let lock = state.lock().unwrap();
let download_agent = lock.game_downloads.get(&game_id).unwrap();
download_agent.clone()
let download_agent = lock.game_downloads.get(&game_id).ok_or("Invalid game ID")?;
Ok(download_agent.clone()) // Clones the Arc, not the underlying data structure
}