mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-13 08:12:44 +10:00
feat(downloads): Added AgentInterfaceData to get information about all downloads in queue
Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user