feat(downloads): Added AgentInterfaceData to get information about all downloads in queue

Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
quexeky
2024-11-16 17:03:37 +11:00
parent f029cbf0b3
commit 63c3cc1096
8 changed files with 98 additions and 44 deletions

View File

@ -26,7 +26,7 @@ async function startGameDownload() {
setInterval(() => { setInterval(() => {
(async () => { (async () => {
const currentProgress = await invoke<number>( const currentProgress = await invoke<number>(
"get_game_download_progress", "get_current_game_download_progress",
{ {
gameId: gameId.value, gameId: gameId.value,
} }

View File

@ -28,7 +28,7 @@ pub struct GameDownloadAgent {
pub progress: ProgressObject, pub progress: ProgressObject,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum GameDownloadError { pub enum GameDownloadError {
CommunicationError(RemoteAccessError), CommunicationError(RemoteAccessError),
ChecksumError, ChecksumError,
@ -50,11 +50,11 @@ impl Display for GameDownloadError {
impl GameDownloadAgent { impl GameDownloadAgent {
pub fn new(id: String, version: String, target_download_dir: usize) -> Self { pub fn new(id: String, version: String, target_download_dir: usize) -> Self {
// Don't run by default // Don't run by default
let status = DownloadThreadControl::new(DownloadThreadControlFlag::Stop); let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop);
Self { Self {
id, id,
version, version,
control_flag: status.clone(), control_flag,
manifest: Mutex::new(None), manifest: Mutex::new(None),
target_download_dir, target_download_dir,
contexts: Mutex::new(Vec::new()), contexts: Mutex::new(Vec::new()),
@ -207,6 +207,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();

View File

@ -36,17 +36,9 @@ pub fn download_game(
} }
#[tauri::command] #[tauri::command]
pub fn get_game_download_progress( pub fn get_current_game_download_progress(
state: tauri::State<'_, Mutex<AppState>>, state: tauri::State<'_, Mutex<AppState>>,
game_id: String,
) -> Result<f64, String> { ) -> Result<f64, String> {
/*
let download_agent = use_download_agent(state, game_id)?;
let progress = &download_agent.progress;
Ok(progress.get_progress())
*/
let progress = state let progress = state
.lock() .lock()
.unwrap() .unwrap()

View File

@ -148,7 +148,7 @@ pub fn download_game_chunk(
.get(chunk_url) .get(chunk_url)
.header("Authorization", header) .header("Authorization", header)
.send() .send()
.map_err(|e| GameDownloadError::CommunicationError(RemoteAccessError::FetchError(e)))?; .map_err(|e| GameDownloadError::CommunicationError(e.into()))?;
let mut destination = DropWriter::new(ctx.path); let mut destination = DropWriter::new(ctx.path);

View File

@ -10,8 +10,8 @@ use std::{
use log::info; use log::info;
use super::{ use super::{
download_agent::GameDownloadAgent, download_agent::{GameDownloadAgent, GameDownloadError},
download_manager_interface::DownloadManagerInterface, download_manager_interface::{AgentInterfaceData, DownloadManagerInterface},
download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag},
progress_object::ProgressObject, progress_object::ProgressObject,
}; };
@ -55,12 +55,13 @@ Behold, my madness - quexeky
pub struct DownloadManager { pub struct DownloadManager {
download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>, download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>,
download_queue: Arc<Mutex<VecDeque<String>>>, download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
command_receiver: Receiver<DownloadManagerSignal>, command_receiver: Receiver<DownloadManagerSignal>,
sender: Sender<DownloadManagerSignal>, sender: Sender<DownloadManagerSignal>,
progress: Arc<Mutex<Option<ProgressObject>>>, progress: Arc<Mutex<Option<ProgressObject>>>,
status: Arc<Mutex<DownloadManagerStatus>>,
current_game_id: Option<String>, // Should be the only game download agent in the map with the "Go" flag current_game_interface: Option<Arc<AgentInterfaceData>>, // Should be the only game download agent in the map with the "Go" flag
active_control_flag: Option<DownloadThreadControl>, active_control_flag: Option<DownloadThreadControl>,
} }
pub enum DownloadManagerSignal { pub enum DownloadManagerSignal {
@ -77,6 +78,21 @@ pub enum DownloadManagerSignal {
/// Tells the Manager to stop the current /// Tells the Manager to stop the current
/// download and return /// download and return
Finish, Finish,
/// Any error which occurs in the agent
Error(GameDownloadError)
}
pub enum DownloadManagerStatus {
Downloading,
Paused,
Empty,
Error(GameDownloadError),
}
#[derive(Clone)]
pub enum GameDownloadStatus {
Downloading,
Paused,
Uninitialised,
Error(GameDownloadError),
} }
impl DownloadManager { impl DownloadManager {
@ -84,13 +100,15 @@ impl DownloadManager {
let queue = Arc::new(Mutex::new(VecDeque::new())); let queue = Arc::new(Mutex::new(VecDeque::new()));
let (command_sender, command_receiver) = channel(); let (command_sender, command_receiver) = channel();
let active_progress = Arc::new(Mutex::new(None)); let active_progress = Arc::new(Mutex::new(None));
let status = Arc::new(Mutex::new(DownloadManagerStatus::Empty));
let manager = Self { let manager = Self {
download_agent_registry: HashMap::new(), download_agent_registry: HashMap::new(),
download_queue: queue.clone(), download_queue: queue.clone(),
command_receiver, command_receiver,
current_game_id: None, current_game_interface: None,
active_control_flag: None, active_control_flag: None,
status: status.clone(),
sender: command_sender.clone(), sender: command_sender.clone(),
progress: active_progress.clone(), progress: active_progress.clone(),
}; };
@ -110,6 +128,7 @@ impl DownloadManager {
match signal { match signal {
DownloadManagerSignal::Go => { DownloadManagerSignal::Go => {
self.manage_go_signal(); self.manage_go_signal();
} }
DownloadManagerSignal::Stop => { DownloadManagerSignal::Stop => {
self.manage_stop_signal(); self.manage_stop_signal();
@ -129,6 +148,9 @@ impl DownloadManager {
} }
return Ok(()); return Ok(());
} }
DownloadManagerSignal::Error(game_download_error) => {
self.manage_error_signal(game_download_error);
},
}; };
} }
} }
@ -142,12 +164,15 @@ impl DownloadManager {
fn manage_completed_signal(&mut self, game_id: String) { fn manage_completed_signal(&mut self, game_id: String) {
info!("Got signal 'Completed'"); info!("Got signal 'Completed'");
if self.current_game_id == Some(game_id.clone()) { if let Some(interface) = &self.current_game_interface {
info!("Popping consumed data"); // When if let chains are stabilised, combine these two statements
self.download_queue.lock().unwrap().pop_front(); if interface.id == game_id {
self.download_agent_registry.remove(&game_id); info!("Popping consumed data");
self.active_control_flag = None; self.download_queue.lock().unwrap().pop_front();
*self.progress.lock().unwrap() = None; self.download_agent_registry.remove(&game_id);
self.active_control_flag = None;
*self.progress.lock().unwrap() = None;
}
} }
self.sender.send(DownloadManagerSignal::Go).unwrap(); self.sender.send(DownloadManagerSignal::Go).unwrap();
} }
@ -164,9 +189,14 @@ impl DownloadManager {
version, version,
target_download_dir, target_download_dir,
)); ));
let agent_status = GameDownloadStatus::Uninitialised;
let interface_data = Arc::new(AgentInterfaceData {
id,
status: Mutex::new(agent_status),
});
self.download_agent_registry self.download_agent_registry
.insert(id.clone(), download_agent); .insert(interface_data.id.clone(), download_agent);
self.download_queue.lock().unwrap().push_back(id); self.download_queue.lock().unwrap().push_back(interface_data);
} }
fn manage_go_signal(&mut self) { fn manage_go_signal(&mut self) {
@ -176,11 +206,12 @@ impl DownloadManager {
let download_agent = { let download_agent = {
let lock = self.download_queue.lock().unwrap(); let lock = self.download_queue.lock().unwrap();
self.download_agent_registry self.download_agent_registry
.get(&lock.front().unwrap().clone()) .get(&lock.front().unwrap().id)
.unwrap() .unwrap()
.clone() .clone()
}; };
self.current_game_id = Some(download_agent.id.clone()); let download_agent_interface = Arc::new(AgentInterfaceData::from(download_agent.clone()));
self.current_game_interface = Some(download_agent_interface);
let progress_object = download_agent.progress.clone(); let progress_object = download_agent.progress.clone();
*self.progress.lock().unwrap() = Some(progress_object); *self.progress.lock().unwrap() = Some(progress_object);
@ -192,14 +223,20 @@ impl DownloadManager {
info!("Spawning download"); info!("Spawning download");
spawn(move || { spawn(move || {
download_agent.download().unwrap(); let signal = match download_agent.download() {
sender Ok(_) => {
.send(DownloadManagerSignal::Completed(download_agent.id.clone())) DownloadManagerSignal::Completed(download_agent.id.clone())
.unwrap(); },
Err(e) => {
DownloadManagerSignal::Error(e)
},
};
sender.send(signal).unwrap();
}); });
info!("Finished spawning Download"); info!("Finished spawning Download");
active_control_flag.set(DownloadThreadControlFlag::Go); active_control_flag.set(DownloadThreadControlFlag::Go);
self.set_status(DownloadManagerStatus::Downloading);
} else if let Some(active_control_flag) = self.active_control_flag.clone() { } else if let Some(active_control_flag) = self.active_control_flag.clone() {
info!("Restarting current download"); info!("Restarting current download");
active_control_flag.set(DownloadThreadControlFlag::Go); active_control_flag.set(DownloadThreadControlFlag::Go);
@ -207,4 +244,13 @@ impl DownloadManager {
info!("Nothing was set"); info!("Nothing was set");
} }
} }
fn manage_error_signal(&self, error: GameDownloadError) {
let current_status = self.current_game_interface.clone().unwrap();
let mut lock = current_status.status.lock().unwrap();
*lock = GameDownloadStatus::Error(error.clone());
self.set_status(DownloadManagerStatus::Error(error));
}
fn set_status(&self, status: DownloadManagerStatus) {
*self.status.lock().unwrap() = status;
}
} }

View File

@ -7,7 +7,7 @@ use std::{
use log::info; use log::info;
use super::{download_manager::DownloadManagerSignal, progress_object::ProgressObject}; use super::{download_agent::GameDownloadAgent, download_manager::{DownloadManagerSignal, DownloadManagerStatus, GameDownloadStatus}, progress_object::ProgressObject};
/// Accessible front-end for the DownloadManager /// Accessible front-end for the DownloadManager
/// ///
@ -21,15 +21,27 @@ use super::{download_manager::DownloadManagerSignal, progress_object::ProgressOb
/// THIS EDITING IS BLOCKING!!! /// THIS EDITING IS BLOCKING!!!
pub struct DownloadManagerInterface { pub struct DownloadManagerInterface {
terminator: JoinHandle<Result<(), ()>>, terminator: JoinHandle<Result<(), ()>>,
download_queue: Arc<Mutex<VecDeque<String>>>, download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
progress: Arc<Mutex<Option<ProgressObject>>>, progress: Arc<Mutex<Option<ProgressObject>>>,
command_sender: Sender<DownloadManagerSignal>, command_sender: Sender<DownloadManagerSignal>,
} }
pub struct AgentInterfaceData {
pub id: String,
pub status: Mutex<GameDownloadStatus>,
}
impl From<Arc<GameDownloadAgent>> for AgentInterfaceData {
fn from(value: Arc<GameDownloadAgent>) -> Self {
Self {
id: value.id.clone(),
status: Mutex::from(GameDownloadStatus::Uninitialised)
}
}
}
impl DownloadManagerInterface { impl DownloadManagerInterface {
pub fn new( pub fn new(
terminator: JoinHandle<Result<(), ()>>, terminator: JoinHandle<Result<(), ()>>,
download_queue: Arc<Mutex<VecDeque<String>>>, download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
progress: Arc<Mutex<Option<ProgressObject>>>, progress: Arc<Mutex<Option<ProgressObject>>>,
command_sender: Sender<DownloadManagerSignal>, command_sender: Sender<DownloadManagerSignal>,
) -> Self { ) -> Self {
@ -55,9 +67,12 @@ impl DownloadManagerInterface {
))?; ))?;
self.command_sender.send(DownloadManagerSignal::Go) self.command_sender.send(DownloadManagerSignal::Go)
} }
pub fn edit(&self) -> MutexGuard<'_, VecDeque<String>> { pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<AgentInterfaceData>>> {
self.download_queue.lock().unwrap() self.download_queue.lock().unwrap()
} }
pub fn read_queue(&self) -> VecDeque<Arc<AgentInterfaceData>> {
self.download_queue.lock().unwrap().clone()
}
pub fn get_current_game_download_progress(&self) -> Option<f64> { pub fn get_current_game_download_progress(&self) -> Option<f64> {
let progress_object = (*self.progress.lock().unwrap()).clone()?; let progress_object = (*self.progress.lock().unwrap()).clone()?;
Some(progress_object.get_progress()) Some(progress_object.get_progress())
@ -95,8 +110,8 @@ impl DownloadManagerInterface {
/// Takes in the locked value from .edit() and attempts to /// Takes in the locked value from .edit() and attempts to
/// get the index of whatever game_id is passed in /// get the index of whatever game_id is passed in
fn get_index_from_id(queue: &mut MutexGuard<'_, VecDeque<String>>, id: String) -> Option<usize> { fn get_index_from_id(queue: &mut MutexGuard<'_, VecDeque<Arc<AgentInterfaceData>>>, id: String) -> Option<usize> {
queue queue
.iter() .iter()
.position(|download_agent| download_agent == &id) .position(|download_agent| download_agent.id == id)
} }

View File

@ -124,7 +124,7 @@ pub fn run() {
add_new_download_dir, add_new_download_dir,
// Downloads // Downloads
download_game, download_game,
get_game_download_progress, get_current_game_download_progress,
]) ])
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.setup(|app| { .setup(|app| {

View File

@ -1,6 +1,6 @@
use std::{ use std::{
fmt::{Display, Formatter}, fmt::{Display, Formatter},
sync::Mutex, sync::{Arc, Mutex},
}; };
use log::{info, warn}; use log::{info, warn};
@ -9,9 +9,9 @@ use url::{ParseError, Url};
use crate::{AppState, AppStatus, DB}; use crate::{AppState, AppStatus, DB};
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum RemoteAccessError { pub enum RemoteAccessError {
FetchError(reqwest::Error), FetchError(Arc<reqwest::Error>),
ParsingError(ParseError), ParsingError(ParseError),
InvalidCodeError(u16), InvalidCodeError(u16),
GenericErrror(String), GenericErrror(String),
@ -32,7 +32,7 @@ impl Display for RemoteAccessError {
impl From<reqwest::Error> for RemoteAccessError { impl From<reqwest::Error> for RemoteAccessError {
fn from(err: reqwest::Error) -> Self { fn from(err: reqwest::Error) -> Self {
RemoteAccessError::FetchError(err) RemoteAccessError::FetchError(Arc::new(err))
} }
} }
impl From<String> for RemoteAccessError { impl From<String> for RemoteAccessError {