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(() => {
(async () => {
const currentProgress = await invoke<number>(
"get_game_download_progress",
"get_current_game_download_progress",
{
gameId: gameId.value,
}

View File

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

View File

@ -36,17 +36,9 @@ pub fn download_game(
}
#[tauri::command]
pub fn get_game_download_progress(
pub fn get_current_game_download_progress(
state: tauri::State<'_, Mutex<AppState>>,
game_id: 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
.lock()
.unwrap()

View File

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

View File

@ -10,8 +10,8 @@ use std::{
use log::info;
use super::{
download_agent::GameDownloadAgent,
download_manager_interface::DownloadManagerInterface,
download_agent::{GameDownloadAgent, GameDownloadError},
download_manager_interface::{AgentInterfaceData, DownloadManagerInterface},
download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag},
progress_object::ProgressObject,
};
@ -55,12 +55,13 @@ Behold, my madness - quexeky
pub struct DownloadManager {
download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>,
download_queue: Arc<Mutex<VecDeque<String>>>,
download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
command_receiver: Receiver<DownloadManagerSignal>,
sender: Sender<DownloadManagerSignal>,
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>,
}
pub enum DownloadManagerSignal {
@ -77,6 +78,21 @@ pub enum DownloadManagerSignal {
/// Tells the Manager to stop the current
/// download and return
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 {
@ -84,13 +100,15 @@ impl DownloadManager {
let queue = Arc::new(Mutex::new(VecDeque::new()));
let (command_sender, command_receiver) = channel();
let active_progress = Arc::new(Mutex::new(None));
let status = Arc::new(Mutex::new(DownloadManagerStatus::Empty));
let manager = Self {
download_agent_registry: HashMap::new(),
download_queue: queue.clone(),
command_receiver,
current_game_id: None,
current_game_interface: None,
active_control_flag: None,
status: status.clone(),
sender: command_sender.clone(),
progress: active_progress.clone(),
};
@ -110,6 +128,7 @@ impl DownloadManager {
match signal {
DownloadManagerSignal::Go => {
self.manage_go_signal();
}
DownloadManagerSignal::Stop => {
self.manage_stop_signal();
@ -129,6 +148,9 @@ impl DownloadManager {
}
return Ok(());
}
DownloadManagerSignal::Error(game_download_error) => {
self.manage_error_signal(game_download_error);
},
};
}
}
@ -142,13 +164,16 @@ impl DownloadManager {
fn manage_completed_signal(&mut self, game_id: String) {
info!("Got signal 'Completed'");
if self.current_game_id == Some(game_id.clone()) {
if let Some(interface) = &self.current_game_interface {
// When if let chains are stabilised, combine these two statements
if interface.id == game_id {
info!("Popping consumed data");
self.download_queue.lock().unwrap().pop_front();
self.download_agent_registry.remove(&game_id);
self.active_control_flag = None;
*self.progress.lock().unwrap() = None;
}
}
self.sender.send(DownloadManagerSignal::Go).unwrap();
}
@ -164,9 +189,14 @@ impl DownloadManager {
version,
target_download_dir,
));
let agent_status = GameDownloadStatus::Uninitialised;
let interface_data = Arc::new(AgentInterfaceData {
id,
status: Mutex::new(agent_status),
});
self.download_agent_registry
.insert(id.clone(), download_agent);
self.download_queue.lock().unwrap().push_back(id);
.insert(interface_data.id.clone(), download_agent);
self.download_queue.lock().unwrap().push_back(interface_data);
}
fn manage_go_signal(&mut self) {
@ -176,11 +206,12 @@ impl DownloadManager {
let download_agent = {
let lock = self.download_queue.lock().unwrap();
self.download_agent_registry
.get(&lock.front().unwrap().clone())
.get(&lock.front().unwrap().id)
.unwrap()
.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();
*self.progress.lock().unwrap() = Some(progress_object);
@ -192,14 +223,20 @@ impl DownloadManager {
info!("Spawning download");
spawn(move || {
download_agent.download().unwrap();
sender
.send(DownloadManagerSignal::Completed(download_agent.id.clone()))
.unwrap();
let signal = match download_agent.download() {
Ok(_) => {
DownloadManagerSignal::Completed(download_agent.id.clone())
},
Err(e) => {
DownloadManagerSignal::Error(e)
},
};
sender.send(signal).unwrap();
});
info!("Finished spawning Download");
active_control_flag.set(DownloadThreadControlFlag::Go);
self.set_status(DownloadManagerStatus::Downloading);
} else if let Some(active_control_flag) = self.active_control_flag.clone() {
info!("Restarting current download");
active_control_flag.set(DownloadThreadControlFlag::Go);
@ -207,4 +244,13 @@ impl DownloadManager {
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 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
///
@ -21,15 +21,27 @@ use super::{download_manager::DownloadManagerSignal, progress_object::ProgressOb
/// THIS EDITING IS BLOCKING!!!
pub struct DownloadManagerInterface {
terminator: JoinHandle<Result<(), ()>>,
download_queue: Arc<Mutex<VecDeque<String>>>,
download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
progress: Arc<Mutex<Option<ProgressObject>>>,
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 {
pub fn new(
terminator: JoinHandle<Result<(), ()>>,
download_queue: Arc<Mutex<VecDeque<String>>>,
download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
progress: Arc<Mutex<Option<ProgressObject>>>,
command_sender: Sender<DownloadManagerSignal>,
) -> Self {
@ -55,9 +67,12 @@ impl DownloadManagerInterface {
))?;
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()
}
pub fn read_queue(&self) -> VecDeque<Arc<AgentInterfaceData>> {
self.download_queue.lock().unwrap().clone()
}
pub fn get_current_game_download_progress(&self) -> Option<f64> {
let progress_object = (*self.progress.lock().unwrap()).clone()?;
Some(progress_object.get_progress())
@ -95,8 +110,8 @@ impl DownloadManagerInterface {
/// Takes in the locked value from .edit() and attempts to
/// 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
.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,
// Downloads
download_game,
get_game_download_progress,
get_current_game_download_progress,
])
.plugin(tauri_plugin_shell::init())
.setup(|app| {

View File

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