refactor(download manager): rename files to what they contain

This commit is contained in:
DecDuck
2024-11-26 19:54:43 +11:00
parent a53d838d05
commit 99c8b39a11
8 changed files with 398 additions and 366 deletions

View File

@ -28,7 +28,6 @@ pub enum DatabaseGameStatus {
Downloading,
Installed,
Updating,
Uninstalling,
}

View File

@ -1,69 +1,20 @@
use std::{
collections::{HashMap, VecDeque},
any::Any,
collections::VecDeque,
sync::{
mpsc::{channel, Receiver, Sender},
Arc, Mutex,
mpsc::{SendError, Sender},
Arc, Mutex, MutexGuard,
},
thread::spawn,
thread::JoinHandle,
};
use log::{info, warn};
use log::info;
use super::{
download_agent::{GameDownloadAgent, GameDownloadError},
download_manager_interface::{AgentInterfaceData, DownloadManager},
download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag},
progress_object::ProgressObject, queue::Queue,
};
/*
Welcome to the download manager, the most overengineered, glorious piece of bullshit.
The download manager takes a queue of game_ids and their associated
GameDownloadAgents, and then, one-by-one, executes them. It provides an interface
to interact with the currently downloading agent, and manage the queue.
When the DownloadManager is initialised, it is designed to provide a reference
which can be used to provide some instructions (the DownloadManagerInterface),
but other than that, it runs without any sort of interruptions.
It does this by opening up two data structures. Primarily is the command_receiver,
and mpsc (multi-channel-single-producer) which allows commands to be sent from
the Interface, and queued up for the Manager to process.
These have been mapped in the DownloadManagerSignal docs.
The other way to interact with the DownloadManager is via the donwload_queue,
which is just a collection of ids which may be rearranged to suit
whichever download queue order is required.
+----------------------------------------------------------------------------+
| DO NOT ATTEMPT TO ADD OR REMOVE FROM THE QUEUE WITHOUT USING SIGNALS!! |
| THIS WILL CAUSE A DESYNC BETWEEN THE DOWNLOAD AGENT REGISTRY AND THE QUEUE |
| WHICH HAS NOT BEEN ACCOUNTED FOR |
+----------------------------------------------------------------------------+
This download queue does not actually own any of the GameDownloadAgents. It is
simply a id-based reference system. The actual Agents are stored in the
download_agent_registry HashMap, as ordering is no issue here. This is why
appending or removing from the download_queue must be done via signals.
Behold, my madness - quexeky
*/
pub struct DownloadManagerBuilder {
download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>,
download_queue: Queue,
command_receiver: Receiver<DownloadManagerSignal>,
sender: Sender<DownloadManagerSignal>,
progress: Arc<Mutex<Option<ProgressObject>>>,
status: Arc<Mutex<DownloadManagerStatus>>,
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 {
/// Resumes (or starts) the DownloadManager
Go,
@ -86,7 +37,7 @@ pub enum DownloadManagerStatus {
Downloading,
Paused,
Empty,
Error,
Error(GameDownloadError),
}
pub enum GameDownloadStatus {
Downloading,
@ -95,174 +46,120 @@ pub enum GameDownloadStatus {
Error,
}
impl DownloadManagerBuilder {
pub fn build() -> DownloadManager {
let queue = Queue::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_interface: None,
active_control_flag: None,
status: status.clone(),
sender: command_sender.clone(),
progress: active_progress.clone(),
};
let terminator = spawn(|| manager.manage_queue());
DownloadManager::new(terminator, queue, active_progress, command_sender)
}
fn manage_queue(mut self) -> Result<(), ()> {
loop {
let signal = match self.command_receiver.recv() {
Ok(signal) => signal,
Err(e) => return Err(()),
};
match signal {
DownloadManagerSignal::Go => {
self.manage_go_signal();
}
DownloadManagerSignal::Stop => {
self.manage_stop_signal();
}
DownloadManagerSignal::Completed(game_id) => {
self.manage_completed_signal(game_id);
}
DownloadManagerSignal::Queue(game_id, version, target_download_dir) => {
self.manage_queue_signal(game_id, version, target_download_dir);
}
DownloadManagerSignal::Finish => {
if let Some(active_control_flag) = self.active_control_flag {
active_control_flag.set(DownloadThreadControlFlag::Stop)
}
return Ok(());
}
DownloadManagerSignal::Error(e) => {
self.manage_error_signal(e);
},
DownloadManagerSignal::Cancel(id) => {
self.manage_cancel_signal(id);
},
};
/// Accessible front-end for the DownloadManager
///
/// The system works entirely through signals, both internally and externally,
/// all of which are accessible through the DownloadManagerSignal type, but
/// should not be used directly. Rather, signals are abstracted through this
/// interface.
///
/// The actual download queue may be accessed through the .edit() function,
/// which provides raw access to the underlying queue.
/// THIS EDITING IS BLOCKING!!!
pub struct DownloadManager {
terminator: JoinHandle<Result<(), ()>>,
download_queue: Queue,
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),
}
}
fn manage_stop_signal(&mut self) {
info!("Got signal 'Stop'");
if let Some(active_control_flag) = self.active_control_flag.clone() {
active_control_flag.set(DownloadThreadControlFlag::Stop);
}
}
fn manage_completed_signal(&mut self, game_id: String) {
info!("Got signal 'Completed'");
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.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();
}
fn manage_queue_signal(&mut self, id: String, version: String, target_download_dir: usize) {
info!("Got signal Queue");
let download_agent = Arc::new(GameDownloadAgent::new(
id.clone(),
version,
target_download_dir,
self.sender.clone()
));
let agent_status = GameDownloadStatus::Uninitialised;
let interface_data = AgentInterfaceData {
id,
status: Mutex::new(agent_status),
};
self.download_agent_registry
.insert(interface_data.id.clone(), download_agent);
self.download_queue.append(interface_data);
}
fn manage_go_signal(&mut self) {
info!("Got signal 'Go'");
if self.active_control_flag.is_none() && !self.download_agent_registry.is_empty() {
info!("Starting download agent");
let download_agent = {
let front = self.download_queue.read().front().unwrap().clone();
self.download_agent_registry
.get(&front.id)
.unwrap()
.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);
let active_control_flag = download_agent.control_flag.clone();
self.active_control_flag = Some(active_control_flag.clone());
let sender = self.sender.clone();
info!("Spawning download");
spawn(move || {
match download_agent.download() {
Ok(_) => {
sender.send(DownloadManagerSignal::Completed(download_agent.id.clone())).unwrap();
},
Err(e) => {
warn!("Download failed");
//todo!() // Account for if the setup_download function fails
},
};
});
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);
} else {
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;
self.set_status(DownloadManagerStatus::Error);
}
fn manage_cancel_signal(&mut self, game_id: String) {
if let Some(current_flag) = &self.active_control_flag {
current_flag.set(DownloadThreadControlFlag::Stop);
self.active_control_flag = None;
*self.progress.lock().unwrap() = None;
}
self.download_agent_registry.remove(&game_id);
let mut lock = self.download_queue.edit();
let index = match lock.iter().position(|interface| interface.id == game_id) {
Some(index) => index,
None => return,
};
lock.remove(index);
self.sender.send(DownloadManagerSignal::Go).unwrap();
info!("{:?}", self.download_agent_registry.iter().map(|x| x.0.clone()).collect::<String>());
}
fn set_status(&self, status: DownloadManagerStatus) {
*self.status.lock().unwrap() = status;
}
}
impl DownloadManager {
pub fn new(
terminator: JoinHandle<Result<(), ()>>,
download_queue: Queue,
progress: Arc<Mutex<Option<ProgressObject>>>,
command_sender: Sender<DownloadManagerSignal>,
) -> Self {
Self {
terminator,
download_queue,
progress,
command_sender,
}
}
pub fn queue_game(
&self,
id: String,
version: String,
target_download_dir: usize,
) -> Result<(), SendError<DownloadManagerSignal>> {
info!("Adding game id {}", id);
self.command_sender.send(DownloadManagerSignal::Queue(
id,
version,
target_download_dir,
))?;
self.command_sender.send(DownloadManagerSignal::Go)
}
pub fn cancel_download(
&self,
game_id: String
) {
self.command_sender.send(DownloadManagerSignal::Cancel(game_id)).unwrap();
}
pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<AgentInterfaceData>>> {
self.download_queue.edit()
}
pub fn read_queue(&self) -> VecDeque<Arc<AgentInterfaceData>> {
self.download_queue.read()
}
pub fn get_current_game_download_progress(&self) -> Option<f64> {
let progress_object = (*self.progress.lock().unwrap()).clone()?;
Some(progress_object.get_progress())
}
pub fn rearrange_string(&self, id: String, new_index: usize) {
let mut queue = self.edit();
let current_index = get_index_from_id(&mut queue, id).unwrap();
let to_move = queue.remove(current_index).unwrap();
queue.insert(new_index, to_move);
}
pub fn rearrange(&self, current_index: usize, new_index: usize) {
let mut queue = self.edit();
let to_move = queue.remove(current_index).unwrap();
queue.insert(new_index, to_move);
}
pub fn remove_from_queue(&self, index: usize) {
self.edit().remove(index);
}
pub fn remove_from_queue_string(&self, id: String) {
let mut queue = self.edit();
let current_index = get_index_from_id(&mut queue, id).unwrap();
queue.remove(current_index);
}
pub fn pause_downloads(&self) -> Result<(), SendError<DownloadManagerSignal>> {
self.command_sender.send(DownloadManagerSignal::Stop)
}
pub fn resume_downloads(&self) -> Result<(), SendError<DownloadManagerSignal>> {
self.command_sender.send(DownloadManagerSignal::Go)
}
pub fn ensure_terminated(self) -> Result<Result<(), ()>, Box<dyn Any + Send>> {
self.command_sender
.send(DownloadManagerSignal::Finish)
.unwrap();
self.terminator.join()
}
}
/// 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<Arc<AgentInterfaceData>>>,
id: String,
) -> Option<usize> {
queue
.iter()
.position(|download_agent| download_agent.id == id)
}

View File

@ -0,0 +1,252 @@
use std::{
collections::HashMap,
sync::{
mpsc::{channel, Receiver, Sender},
Arc, Mutex,
},
thread::spawn,
};
use log::{error, info, warn};
use super::{
download_agent::{GameDownloadAgent, GameDownloadError},
download_manager::{
AgentInterfaceData, DownloadManager, DownloadManagerSignal, DownloadManagerStatus,
GameDownloadStatus,
},
download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag},
progress_object::ProgressObject,
queue::Queue,
};
/*
Welcome to the download manager, the most overengineered, glorious piece of bullshit.
The download manager takes a queue of game_ids and their associated
GameDownloadAgents, and then, one-by-one, executes them. It provides an interface
to interact with the currently downloading agent, and manage the queue.
When the DownloadManager is initialised, it is designed to provide a reference
which can be used to provide some instructions (the DownloadManagerInterface),
but other than that, it runs without any sort of interruptions.
It does this by opening up two data structures. Primarily is the command_receiver,
and mpsc (multi-channel-single-producer) which allows commands to be sent from
the Interface, and queued up for the Manager to process.
These have been mapped in the DownloadManagerSignal docs.
The other way to interact with the DownloadManager is via the donwload_queue,
which is just a collection of ids which may be rearranged to suit
whichever download queue order is required.
+----------------------------------------------------------------------------+
| DO NOT ATTEMPT TO ADD OR REMOVE FROM THE QUEUE WITHOUT USING SIGNALS!! |
| THIS WILL CAUSE A DESYNC BETWEEN THE DOWNLOAD AGENT REGISTRY AND THE QUEUE |
| WHICH HAS NOT BEEN ACCOUNTED FOR |
+----------------------------------------------------------------------------+
This download queue does not actually own any of the GameDownloadAgents. It is
simply a id-based reference system. The actual Agents are stored in the
download_agent_registry HashMap, as ordering is no issue here. This is why
appending or removing from the download_queue must be done via signals.
Behold, my madness - quexeky
*/
pub struct DownloadManagerBuilder {
download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>,
download_queue: Queue,
command_receiver: Receiver<DownloadManagerSignal>,
sender: Sender<DownloadManagerSignal>,
progress: Arc<Mutex<Option<ProgressObject>>>,
status: Arc<Mutex<DownloadManagerStatus>>,
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>,
}
impl DownloadManagerBuilder {
pub fn build() -> DownloadManager {
let queue = Queue::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_interface: None,
active_control_flag: None,
status: status.clone(),
sender: command_sender.clone(),
progress: active_progress.clone(),
};
let terminator = spawn(|| manager.manage_queue());
DownloadManager::new(terminator, queue, active_progress, command_sender)
}
fn manage_queue(mut self) -> Result<(), ()> {
loop {
let signal = match self.command_receiver.recv() {
Ok(signal) => signal,
Err(_) => return Err(()),
};
match signal {
DownloadManagerSignal::Go => {
self.manage_go_signal();
}
DownloadManagerSignal::Stop => {
self.manage_stop_signal();
}
DownloadManagerSignal::Completed(game_id) => {
self.manage_completed_signal(game_id);
}
DownloadManagerSignal::Queue(game_id, version, target_download_dir) => {
self.manage_queue_signal(game_id, version, target_download_dir);
}
DownloadManagerSignal::Finish => {
if let Some(active_control_flag) = self.active_control_flag {
active_control_flag.set(DownloadThreadControlFlag::Stop)
}
return Ok(());
}
DownloadManagerSignal::Error(e) => {
self.manage_error_signal(e);
}
DownloadManagerSignal::Cancel(id) => {
self.manage_cancel_signal(id);
}
};
}
}
fn manage_stop_signal(&mut self) {
info!("Got signal 'Stop'");
if let Some(active_control_flag) = self.active_control_flag.clone() {
active_control_flag.set(DownloadThreadControlFlag::Stop);
}
}
fn manage_completed_signal(&mut self, game_id: String) {
info!("Got signal 'Completed'");
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.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();
}
fn manage_queue_signal(&mut self, id: String, version: String, target_download_dir: usize) {
info!("Got signal Queue");
let download_agent = Arc::new(GameDownloadAgent::new(
id.clone(),
version,
target_download_dir,
self.sender.clone(),
));
let agent_status = GameDownloadStatus::Uninitialised;
let interface_data = AgentInterfaceData {
id,
status: Mutex::new(agent_status),
};
self.download_agent_registry
.insert(interface_data.id.clone(), download_agent);
self.download_queue.append(interface_data);
}
fn manage_go_signal(&mut self) {
info!("Got signal 'Go'");
if self.active_control_flag.is_none() && !self.download_agent_registry.is_empty() {
info!("Starting download agent");
let download_agent = {
let front = self.download_queue.read().front().unwrap().clone();
self.download_agent_registry.get(&front.id).unwrap().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);
let active_control_flag = download_agent.control_flag.clone();
self.active_control_flag = Some(active_control_flag.clone());
let sender = self.sender.clone();
info!("Spawning download");
spawn(move || {
match download_agent.download() {
Ok(_) => {
// TODO wrap this pattern in a macro
let result = sender
.send(DownloadManagerSignal::Completed(download_agent.id.clone()));
if let Err(err) = result {
error!("{}", err);
}
}
Err(err) => {
let result = sender.send(DownloadManagerSignal::Error(err));
if let Err(err) = result {
error!("{}", err);
}
}
};
});
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);
} else {
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;
self.set_status(DownloadManagerStatus::Error(error));
}
fn manage_cancel_signal(&mut self, game_id: String) {
if let Some(current_flag) = &self.active_control_flag {
current_flag.set(DownloadThreadControlFlag::Stop);
self.active_control_flag = None;
*self.progress.lock().unwrap() = None;
}
self.download_agent_registry.remove(&game_id);
let mut lock = self.download_queue.edit();
let index = match lock.iter().position(|interface| interface.id == game_id) {
Some(index) => index,
None => return,
};
lock.remove(index);
self.sender.send(DownloadManagerSignal::Go).unwrap();
info!(
"{:?}",
self.download_agent_registry
.iter()
.map(|x| x.0.clone())
.collect::<String>()
);
}
fn set_status(&self, status: DownloadManagerStatus) {
*self.status.lock().unwrap() = status;
}
}

View File

@ -1,135 +0,0 @@
use std::{
any::Any,
collections::VecDeque,
sync::{
mpsc::{SendError, Sender},
Arc, Mutex, MutexGuard,
},
thread::JoinHandle,
};
use log::info;
use super::{
download_agent::GameDownloadAgent,
download_manager::{DownloadManagerSignal, GameDownloadStatus},
progress_object::ProgressObject, queue::Queue,
};
/// Accessible front-end for the DownloadManager
///
/// The system works entirely through signals, both internally and externally,
/// all of which are accessible through the DownloadManagerSignal type, but
/// should not be used directly. Rather, signals are abstracted through this
/// interface.
///
/// The actual download queue may be accessed through the .edit() function,
/// which provides raw access to the underlying queue.
/// THIS EDITING IS BLOCKING!!!
pub struct DownloadManager {
terminator: JoinHandle<Result<(), ()>>,
download_queue: Queue,
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 DownloadManager {
pub fn new(
terminator: JoinHandle<Result<(), ()>>,
download_queue: Queue,
progress: Arc<Mutex<Option<ProgressObject>>>,
command_sender: Sender<DownloadManagerSignal>,
) -> Self {
Self {
terminator,
download_queue,
progress,
command_sender,
}
}
pub fn queue_game(
&self,
id: String,
version: String,
target_download_dir: usize,
) -> Result<(), SendError<DownloadManagerSignal>> {
info!("Adding game id {}", id);
self.command_sender.send(DownloadManagerSignal::Queue(
id,
version,
target_download_dir,
))?;
self.command_sender.send(DownloadManagerSignal::Go)
}
pub fn cancel_download(
&self,
game_id: String
) {
self.command_sender.send(DownloadManagerSignal::Cancel(game_id)).unwrap();
}
pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<AgentInterfaceData>>> {
self.download_queue.edit()
}
pub fn read_queue(&self) -> VecDeque<Arc<AgentInterfaceData>> {
self.download_queue.read()
}
pub fn get_current_game_download_progress(&self) -> Option<f64> {
let progress_object = (*self.progress.lock().unwrap()).clone()?;
Some(progress_object.get_progress())
}
pub fn rearrange_string(&self, id: String, new_index: usize) {
let mut queue = self.edit();
let current_index = get_index_from_id(&mut queue, id).unwrap();
let to_move = queue.remove(current_index).unwrap();
queue.insert(new_index, to_move);
}
pub fn rearrange(&self, current_index: usize, new_index: usize) {
let mut queue = self.edit();
let to_move = queue.remove(current_index).unwrap();
queue.insert(new_index, to_move);
}
pub fn remove_from_queue(&self, index: usize) {
self.edit().remove(index);
}
pub fn remove_from_queue_string(&self, id: String) {
let mut queue = self.edit();
let current_index = get_index_from_id(&mut queue, id).unwrap();
queue.remove(current_index);
}
pub fn pause_downloads(&self) -> Result<(), SendError<DownloadManagerSignal>> {
self.command_sender.send(DownloadManagerSignal::Stop)
}
pub fn resume_downloads(&self) -> Result<(), SendError<DownloadManagerSignal>> {
self.command_sender.send(DownloadManagerSignal::Go)
}
pub fn ensure_terminated(self) -> Result<Result<(), ()>, Box<dyn Any + Send>> {
self.command_sender
.send(DownloadManagerSignal::Finish)
.unwrap();
self.terminator.join()
}
}
/// 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<Arc<AgentInterfaceData>>>,
id: String,
) -> Option<usize> {
queue
.iter()
.position(|download_agent| download_agent.id == id)
}

View File

@ -1,8 +1,8 @@
pub mod download_agent;
pub mod download_commands;
mod download_logic;
pub mod download_manager_builder;
pub mod download_manager;
pub mod download_manager_interface;
mod download_thread_control_flag;
mod manifest;
mod progress_object;

View File

@ -1,6 +1,6 @@
use std::{collections::VecDeque, sync::{Arc, Mutex, MutexGuard}};
use super::download_manager_interface::AgentInterfaceData;
use super::download_manager::AgentInterfaceData;
#[derive(Clone)]
pub struct Queue {

View File

@ -10,13 +10,16 @@ mod tests;
use crate::db::DatabaseImpls;
use auth::{auth_initiate, generate_authorization_header, recieve_handshake, retry_connect};
use db::{add_download_dir, delete_download_dir, fetch_download_dir_stats, DatabaseInterface, DATA_ROOT_DIR};
use db::{
add_download_dir, delete_download_dir, fetch_download_dir_stats, DatabaseInterface,
DATA_ROOT_DIR,
};
use downloads::download_commands::*;
use downloads::download_manager::DownloadManagerBuilder;
use downloads::download_manager_interface::DownloadManager;
use downloads::download_manager_builder::DownloadManagerBuilder;
use downloads::download_manager::DownloadManager;
use env_logger::Env;
use http::{header::*, response::Builder as ResponseBuilder};
use library::{fetch_game, fetch_library, Game};
use library::{fetch_game, fetch_game_status, fetch_library, Game};
use log::{debug, info};
use remote::{gen_drop_url, use_remote, RemoteAccessError};
use serde::{Deserialize, Serialize};
@ -130,6 +133,7 @@ pub fn run() {
add_download_dir,
delete_download_dir,
fetch_download_dir_stats,
fetch_game_status,
// Downloads
download_game,
get_current_game_download_progress,

View File

@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
use serde_json::json;
use tauri::{AppHandle, Manager};
use crate::db;
use crate::db::DatabaseGameStatus;
use crate::db::DatabaseImpls;
use crate::remote::RemoteAccessError;
@ -109,3 +110,17 @@ pub fn fetch_game(id: String, app: tauri::AppHandle) -> Result<String, String> {
Ok(result.unwrap())
}
#[tauri::command]
pub fn fetch_game_status(id: String) -> Result<DatabaseGameStatus, String> {
let db_handle = DB.borrow_data().unwrap();
let status = db_handle
.games
.games_statuses
.get(&id)
.unwrap_or(&DatabaseGameStatus::Remote)
.clone();
drop(db_handle);
return Ok(status);
}