chore(download manager): Renamed most instances of "game" outside of actual game downloads

Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
quexeky
2024-12-30 21:29:14 +11:00
parent 88bece5c29
commit a4a4c3e996
10 changed files with 183 additions and 178 deletions
+14 -13
View File
@@ -23,7 +23,7 @@ pub struct DatabaseAuth {
// Strings are version names for a particular game // Strings are version names for a particular game
#[derive(Serialize, Clone, Deserialize)] #[derive(Serialize, Clone, Deserialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum GameStatus { pub enum ApplicationStatus {
Remote {}, Remote {},
SetupRequired { SetupRequired {
version_name: String, version_name: String,
@@ -37,7 +37,7 @@ pub enum GameStatus {
// Stuff that shouldn't be synced to disk // Stuff that shouldn't be synced to disk
#[derive(Clone, Serialize)] #[derive(Clone, Serialize)]
pub enum GameTransientStatus { pub enum ApplicationTransientStatus {
Downloading { version_name: String }, Downloading { version_name: String },
Uninstalling {}, Uninstalling {},
Updating { version_name: String }, Updating { version_name: String },
@@ -46,7 +46,7 @@ pub enum GameTransientStatus {
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct GameVersion { pub struct ApplicationVersion {
pub version_index: usize, pub version_index: usize,
pub version_name: String, pub version_name: String,
pub launch_command: String, pub launch_command: String,
@@ -55,14 +55,15 @@ pub struct GameVersion {
} }
#[derive(Serialize, Clone, Deserialize)] #[derive(Serialize, Clone, Deserialize)]
pub struct DatabaseGames { #[serde(rename_all = "camelCase")]
pub struct DatabaseApplications {
pub install_dirs: Vec<String>, pub install_dirs: Vec<String>,
// Guaranteed to exist if the game also exists in the app state map // Guaranteed to exist if the game also exists in the app state map
pub statuses: HashMap<String, GameStatus>, pub statuses: HashMap<String, ApplicationStatus>,
pub versions: HashMap<String, HashMap<String, GameVersion>>, pub versions: HashMap<String, HashMap<String, ApplicationVersion>>,
#[serde(skip)] #[serde(skip)]
pub transient_statuses: HashMap<String, GameTransientStatus>, pub transient_statuses: HashMap<String, ApplicationTransientStatus>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
@@ -86,7 +87,7 @@ pub struct Database {
pub settings: Settings, pub settings: Settings,
pub auth: Option<DatabaseAuth>, pub auth: Option<DatabaseAuth>,
pub base_url: String, pub base_url: String,
pub games: DatabaseGames, pub applications: DatabaseApplications,
} }
pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> = pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> =
LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop"))); LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop")));
@@ -136,7 +137,7 @@ impl DatabaseImpls for DatabaseInterface {
settings: Settings::default(), settings: Settings::default(),
auth: None, auth: None,
base_url: "".to_string(), base_url: "".to_string(),
games: DatabaseGames { applications: DatabaseApplications {
install_dirs: vec![games_base_dir.to_str().unwrap().to_string()], install_dirs: vec![games_base_dir.to_str().unwrap().to_string()],
statuses: HashMap::new(), statuses: HashMap::new(),
transient_statuses: HashMap::new(), transient_statuses: HashMap::new(),
@@ -187,10 +188,10 @@ pub fn add_download_dir(new_dir: String) -> Result<(), String> {
// Add it to the dictionary // Add it to the dictionary
let mut lock = DB.borrow_data_mut().unwrap(); let mut lock = DB.borrow_data_mut().unwrap();
if lock.games.install_dirs.contains(&new_dir) { if lock.applications.install_dirs.contains(&new_dir) {
return Err("Download directory already used".to_string()); return Err("Download directory already used".to_string());
} }
lock.games.install_dirs.push(new_dir); lock.applications.install_dirs.push(new_dir);
drop(lock); drop(lock);
DB.save().unwrap(); DB.save().unwrap();
@@ -200,7 +201,7 @@ pub fn add_download_dir(new_dir: String) -> Result<(), String> {
#[tauri::command] #[tauri::command]
pub fn delete_download_dir(index: usize) -> Result<(), String> { pub fn delete_download_dir(index: usize) -> Result<(), String> {
let mut lock = DB.borrow_data_mut().unwrap(); let mut lock = DB.borrow_data_mut().unwrap();
lock.games.install_dirs.remove(index); lock.applications.install_dirs.remove(index);
drop(lock); drop(lock);
DB.save().unwrap(); DB.save().unwrap();
@@ -212,7 +213,7 @@ pub fn delete_download_dir(index: usize) -> Result<(), String> {
#[tauri::command] #[tauri::command]
pub fn fetch_download_dir_stats() -> Result<Vec<String>, String> { pub fn fetch_download_dir_stats() -> Result<Vec<String>, String> {
let lock = DB.borrow_data().unwrap(); let lock = DB.borrow_data().unwrap();
let directories = lock.games.install_dirs.clone(); let directories = lock.applications.install_dirs.clone();
drop(lock); drop(lock);
Ok(directories) Ok(directories)
@@ -12,18 +12,23 @@ use std::{
use log::info; use log::info;
use serde::Serialize; use serde::Serialize;
use crate::downloads::download_agent::{GameDownloadAgent, GameDownloadError}; use crate::downloads::download_agent::GameDownloadError;
use super::{download_manager_builder::CurrentProgressObject, progress_object::ProgressObject, queue::Queue}; use super::{download_manager_builder::{CurrentProgressObject, DownloadableQueueStandin}, downloadable::Downloadable, queue::Queue};
pub enum DownloadType {
Game,
Tool,
}
pub enum DownloadManagerSignal { pub enum DownloadManagerSignal {
/// Resumes (or starts) the DownloadManager /// Resumes (or starts) the DownloadManager
Go, Go,
/// Pauses the DownloadManager /// Pauses the DownloadManager
Stop, Stop,
/// Called when a GameDownloadAgent has fully completed a download. /// Called when a DownloadAgent has fully completed a download.
Completed(String), Completed(String),
/// Generates and appends a GameDownloadAgent /// Generates and appends a DownloadAgent
/// to the registry and queue /// to the registry and queue
Queue(String, String, usize), Queue(String, String, usize),
/// Tells the Manager to stop the current /// Tells the Manager to stop the current
@@ -32,15 +37,15 @@ pub enum DownloadManagerSignal {
Finish, Finish,
/// Stops (but doesn't remove) current download /// Stops (but doesn't remove) current download
Cancel, Cancel,
/// Removes a given game /// Removes a given application
Remove(String), Remove(String),
/// Any error which occurs in the agent /// Any error which occurs in the agent
Error(GameDownloadError), Error(GameDownloadError),
/// Pushes UI update /// Pushes UI update
UpdateUIQueue, UpdateUIQueue,
UpdateUIStats(usize, usize), //kb/s and seconds UpdateUIStats(usize, usize), //kb/s and seconds
/// Uninstall game /// Uninstall download
/// Takes game ID /// Takes download ID
Uninstall(String), Uninstall(String),
} }
@@ -63,7 +68,7 @@ impl Serialize for DownloadManagerStatus {
} }
#[derive(Serialize, Clone)] #[derive(Serialize, Clone)]
pub enum GameDownloadStatus { pub enum DownloadStatus {
Queued, Queued,
Downloading, Downloading,
Error, Error,
@@ -85,23 +90,18 @@ pub struct DownloadManager {
progress: CurrentProgressObject, progress: CurrentProgressObject,
command_sender: Sender<DownloadManagerSignal>, command_sender: Sender<DownloadManagerSignal>,
} }
pub struct GameDownloadAgentQueueStandin { impl<T: Downloadable> From<Arc<T>> for DownloadableQueueStandin {
pub id: String, fn from(value: Arc<T>) -> Self {
pub status: Mutex<GameDownloadStatus>,
pub progress: Arc<ProgressObject>,
}
impl From<Arc<GameDownloadAgent>> for GameDownloadAgentQueueStandin {
fn from(value: Arc<GameDownloadAgent>) -> Self {
Self { Self {
id: value.id.clone(), id: value.id(),
status: Mutex::from(GameDownloadStatus::Queued), status: Mutex::from(DownloadStatus::Queued),
progress: value.progress.clone(), progress: value.progress().clone(),
} }
} }
} }
impl Debug for GameDownloadAgentQueueStandin { impl Debug for DownloadableQueueStandin {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("GameDownloadAgentQueueStandin") f.debug_struct("DownloadableQueueStandin")
.field("id", &self.id) .field("id", &self.id)
.finish() .finish()
} }
@@ -123,13 +123,13 @@ impl DownloadManager {
} }
} }
pub fn queue_game( pub fn queue_download(
&self, &self,
id: String, id: String,
version: String, version: String,
target_download_dir: usize, target_download_dir: usize,
) -> Result<(), SendError<DownloadManagerSignal>> { ) -> Result<(), SendError<DownloadManagerSignal>> {
info!("Adding game id {}", id); info!("Adding download id {}", id);
self.command_sender.send(DownloadManagerSignal::Queue( self.command_sender.send(DownloadManagerSignal::Queue(
id, id,
version, version,
@@ -137,13 +137,13 @@ impl DownloadManager {
))?; ))?;
self.command_sender.send(DownloadManagerSignal::Go) self.command_sender.send(DownloadManagerSignal::Go)
} }
pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<GameDownloadAgentQueueStandin>>> { pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<DownloadableQueueStandin>>> {
self.download_queue.edit() self.download_queue.edit()
} }
pub fn read_queue(&self) -> VecDeque<Arc<GameDownloadAgentQueueStandin>> { pub fn read_queue(&self) -> VecDeque<Arc<DownloadableQueueStandin>> {
self.download_queue.read() self.download_queue.read()
} }
pub fn get_current_game_download_progress(&self) -> Option<f64> { pub fn get_current_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())
} }
@@ -156,9 +156,9 @@ impl DownloadManager {
.send(DownloadManagerSignal::UpdateUIQueue) .send(DownloadManagerSignal::UpdateUIQueue)
.unwrap(); .unwrap();
} }
pub fn cancel(&self, game_id: String) { pub fn cancel(&self, id: String) {
self.command_sender self.command_sender
.send(DownloadManagerSignal::Remove(game_id)) .send(DownloadManagerSignal::Remove(id))
.unwrap(); .unwrap();
} }
pub fn rearrange(&self, current_index: usize, new_index: usize) { pub fn rearrange(&self, current_index: usize, new_index: usize) {
@@ -202,17 +202,17 @@ impl DownloadManager {
.unwrap(); .unwrap();
self.terminator.join() self.terminator.join()
} }
pub fn uninstall_game(&self, game_id: String) { pub fn uninstall_application(&self, id: String) {
self.command_sender self.command_sender
.send(DownloadManagerSignal::Uninstall(game_id)) .send(DownloadManagerSignal::Uninstall(id))
.unwrap(); .unwrap();
} }
} }
/// 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 id is passed in
fn get_index_from_id( fn get_index_from_id(
queue: &mut MutexGuard<'_, VecDeque<Arc<GameDownloadAgentQueueStandin>>>, queue: &mut MutexGuard<'_, VecDeque<Arc<DownloadableQueueStandin>>>,
id: String, id: String,
) -> Option<usize> { ) -> Option<usize> {
queue queue
@@ -12,20 +12,20 @@ use log::{error, info};
use tauri::{AppHandle, Emitter}; use tauri::{AppHandle, Emitter};
use crate::{ use crate::{
db::{Database, GameStatus, GameTransientStatus}, download_manager::download_manager::GameDownloadStatus, downloads::download_agent::{GameDownloadAgent, GameDownloadError}, library::{ db::{Database, ApplicationStatus, ApplicationTransientStatus}, download_manager::download_manager::DownloadStatus, downloads::download_agent::{GameDownloadAgent, GameDownloadError}, library::{
on_game_complete, push_game_update, QueueUpdateEvent, on_game_complete, push_application_update, QueueUpdateEvent,
QueueUpdateEventQueueData, StatsUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent,
}, state::GameStatusManager, DB }, state::GameStatusManager, DB
}; };
use super::{download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus, GameDownloadAgentQueueStandin}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, downloadable::Downloadable, progress_object::ProgressObject, queue::Queue}; use super::{download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus}, download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, downloadable::Downloadable, progress_object::ProgressObject, queue::Queue};
/* /*
Welcome to the download manager, the most overengineered, glorious piece of bullshit. Welcome to the download manager, the most overengineered, glorious piece of bullshit.
The download manager takes a queue of game_ids and their associated The download manager takes a queue of ids and their associated
GameDownloadAgents, and then, one-by-one, executes them. It provides an interface DownloadAgents, and then, one-by-one, executes them. It provides an interface
to interact with the currently downloading agent, and manage the queue. to interact with the currently downloading agent, and manage the queue.
When the DownloadManager is initialised, it is designed to provide a reference When the DownloadManager is initialised, it is designed to provide a reference
@@ -48,7 +48,7 @@ whichever download queue order is required.
| WHICH HAS NOT BEEN ACCOUNTED FOR | | WHICH HAS NOT BEEN ACCOUNTED FOR |
+----------------------------------------------------------------------------+ +----------------------------------------------------------------------------+
This download queue does not actually own any of the GameDownloadAgents. It is This download queue does not actually own any of the DownloadAgents. It is
simply a id-based reference system. The actual Agents are stored in the 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 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. appending or removing from the download_queue must be done via signals.
@@ -70,10 +70,15 @@ pub struct DownloadManagerBuilder {
status: Arc<Mutex<DownloadManagerStatus>>, status: Arc<Mutex<DownloadManagerStatus>>,
app_handle: AppHandle, app_handle: AppHandle,
current_download_agent: Option<Arc<GameDownloadAgentQueueStandin>>, // Should be the only game download agent in the map with the "Go" flag current_download_agent: Option<Arc<DownloadableQueueStandin>>, // Should be the only download agent in the map with the "Go" flag
current_download_thread: Mutex<Option<JoinHandle<()>>>, current_download_thread: Mutex<Option<JoinHandle<()>>>,
active_control_flag: Option<DownloadThreadControl>, active_control_flag: Option<DownloadThreadControl>,
} }
pub struct DownloadableQueueStandin {
pub id: String,
pub status: Mutex<DownloadStatus>,
pub progress: Arc<ProgressObject>,
}
impl DownloadManagerBuilder { impl DownloadManagerBuilder {
pub fn build(app_handle: AppHandle) -> DownloadManager { pub fn build(app_handle: AppHandle) -> DownloadManager {
@@ -101,7 +106,7 @@ impl DownloadManagerBuilder {
DownloadManager::new(terminator, queue, active_progress, command_sender) DownloadManager::new(terminator, queue, active_progress, command_sender)
} }
fn set_game_status<F: FnOnce(&mut RwLockWriteGuard<'_, Database>, &String)>( fn set_download_status<F: FnOnce(&mut RwLockWriteGuard<'_, Database>, &String)>(
&self, &self,
id: String, id: String,
setter: F, setter: F,
@@ -113,7 +118,7 @@ impl DownloadManagerBuilder {
let status = GameStatusManager::fetch_state(&id); let status = GameStatusManager::fetch_state(&id);
push_game_update(&self.app_handle, id, status); push_application_update(&self.app_handle, id, status);
} }
fn push_ui_stats_update(&self, kbs: usize, time: usize) { fn push_ui_stats_update(&self, kbs: usize, time: usize) {
@@ -157,9 +162,9 @@ impl DownloadManagerBuilder {
drop(download_thread_lock); drop(download_thread_lock);
} }
fn remove_and_cleanup_front_game(&mut self, game_id: &String) -> DownloadAgent { fn remove_and_cleanup_front_download(&mut self, id: &String) -> DownloadAgent {
self.download_queue.pop_front(); self.download_queue.pop_front();
let download_agent = self.download_agent_registry.remove(game_id).unwrap(); let download_agent = self.download_agent_registry.remove(id).unwrap();
self.cleanup_current_download(); self.cleanup_current_download();
download_agent download_agent
} }
@@ -190,11 +195,11 @@ impl DownloadManagerBuilder {
DownloadManagerSignal::Stop => { DownloadManagerSignal::Stop => {
self.manage_stop_signal(); self.manage_stop_signal();
} }
DownloadManagerSignal::Completed(game_id) => { DownloadManagerSignal::Completed(id) => {
self.manage_completed_signal(game_id); self.manage_completed_signal(id);
} }
DownloadManagerSignal::Queue(game_id, version, target_download_dir) => { DownloadManagerSignal::Queue(id, version, target_download_dir) => {
self.manage_queue_signal(game_id, version, target_download_dir); self.manage_queue_signal(id, version, target_download_dir);
} }
DownloadManagerSignal::Error(e) => { DownloadManagerSignal::Error(e) => {
self.manage_error_signal(e); self.manage_error_signal(e);
@@ -212,54 +217,54 @@ impl DownloadManagerBuilder {
self.stop_and_wait_current_download(); self.stop_and_wait_current_download();
return Ok(()); return Ok(());
} }
DownloadManagerSignal::Remove(game_id) => { DownloadManagerSignal::Remove(id) => {
self.manage_remove_game_queue(game_id); self.manage_remove_download_from_queue(id);
} }
DownloadManagerSignal::Uninstall(game_id) => { DownloadManagerSignal::Uninstall(id) => {
self.uninstall_game(game_id); self.uninstall_application(id);
} }
}; };
} }
} }
fn uninstall_game(&mut self, game_id: String) { fn uninstall_application(&mut self, id: String) {
// Removes the game if it's in the queue // Removes the download if it's in the queue
self.manage_remove_game_queue(game_id.clone()); self.manage_remove_download_from_queue(id.clone());
let mut db_handle = DB.borrow_data_mut().unwrap(); let mut db_handle = DB.borrow_data_mut().unwrap();
db_handle db_handle
.games .applications
.transient_statuses .transient_statuses
.entry(game_id.clone()) .entry(id.clone())
.and_modify(|v| *v = GameTransientStatus::Uninstalling {}); .and_modify(|v| *v = ApplicationTransientStatus::Uninstalling {});
push_game_update( push_application_update(
&self.app_handle, &self.app_handle,
game_id.clone(), id.clone(),
(None, Some(GameTransientStatus::Uninstalling {})), (None, Some(ApplicationTransientStatus::Uninstalling {})),
); );
let previous_state = db_handle.games.statuses.get(&game_id).cloned(); let previous_state = db_handle.applications.statuses.get(&id).cloned();
if previous_state.is_none() { if previous_state.is_none() {
info!("uninstall job doesn't have previous state, failing silently"); info!("uninstall job doesn't have previous state, failing silently");
return; return;
} }
let previous_state = previous_state.unwrap(); let previous_state = previous_state.unwrap();
if let Some((version_name, install_dir)) = match previous_state { if let Some((version_name, install_dir)) = match previous_state {
GameStatus::Installed { ApplicationStatus::Installed {
version_name, version_name,
install_dir, install_dir,
} => Some((version_name, install_dir)), } => Some((version_name, install_dir)),
GameStatus::SetupRequired { ApplicationStatus::SetupRequired {
version_name, version_name,
install_dir, install_dir,
} => Some((version_name, install_dir)), } => Some((version_name, install_dir)),
_ => None, _ => None,
} { } {
db_handle db_handle
.games .applications
.transient_statuses .transient_statuses
.entry(game_id.clone()) .entry(id.clone())
.and_modify(|v| *v = GameTransientStatus::Uninstalling {}); .and_modify(|v| *v = ApplicationTransientStatus::Uninstalling {});
drop(db_handle); drop(db_handle);
let sender = self.sender.clone(); let sender = self.sender.clone();
@@ -274,36 +279,36 @@ impl DownloadManagerBuilder {
} }
Ok(_) => { Ok(_) => {
let mut db_handle = DB.borrow_data_mut().unwrap(); let mut db_handle = DB.borrow_data_mut().unwrap();
db_handle.games.transient_statuses.remove(&game_id); db_handle.applications.transient_statuses.remove(&id);
db_handle db_handle
.games .applications
.statuses .statuses
.entry(game_id.clone()) .entry(id.clone())
.and_modify(|e| *e = GameStatus::Remote {}); .and_modify(|e| *e = ApplicationStatus::Remote {});
drop(db_handle); drop(db_handle);
DB.save().unwrap(); DB.save().unwrap();
info!("uninstalled {}", game_id); info!("uninstalled {}", id);
push_game_update(&app_handle, game_id, (Some(GameStatus::Remote {}), None)); push_application_update(&app_handle, id, (Some(ApplicationStatus::Remote {}), None));
} }
}); });
} }
} }
fn manage_remove_game_queue(&mut self, game_id: String) { fn manage_remove_download_from_queue(&mut self, id: String) {
if let Some(current_download) = &self.current_download_agent { if let Some(current_download) = &self.current_download_agent {
if current_download.id == game_id { if current_download.id == id {
self.manage_cancel_signal(); self.manage_cancel_signal();
} }
} }
let index = self.download_queue.get_by_id(game_id.clone()); let index = self.download_queue.get_by_id(id.clone());
if let Some(index) = index { if let Some(index) = index {
let mut queue_handle = self.download_queue.edit(); let mut queue_handle = self.download_queue.edit();
queue_handle.remove(index); queue_handle.remove(index);
self.set_game_status(game_id, |db_handle, id| { self.set_download_status(id, |db_handle, id| {
db_handle.games.transient_statuses.remove(id); db_handle.applications.transient_statuses.remove(id);
}); });
drop(queue_handle); drop(queue_handle);
} }
@@ -323,13 +328,13 @@ impl DownloadManagerBuilder {
} }
} }
fn manage_completed_signal(&mut self, game_id: String) { fn manage_completed_signal(&mut self, id: String) {
info!("Got signal 'Completed'"); info!("Got signal 'Completed'");
if let Some(interface) = &self.current_download_agent { if let Some(interface) = &self.current_download_agent {
// When if let chains are stabilised, combine these two statements // When if let chains are stabilised, combine these two statements
if interface.id == game_id { if interface.id == id {
info!("Popping consumed data"); info!("Popping consumed data");
let download_agent = self.remove_and_cleanup_front_game(&game_id); let download_agent = self.remove_and_cleanup_front_download(&id);
let download_agent_lock = download_agent.lock().unwrap(); let download_agent_lock = download_agent.lock().unwrap();
let version = download_agent_lock.version(); let version = download_agent_lock.version();
@@ -338,7 +343,7 @@ impl DownloadManagerBuilder {
drop(download_agent_lock); drop(download_agent_lock);
if let Err(error) = if let Err(error) =
on_game_complete(game_id, version, install_dir, &self.app_handle) on_game_complete(id, version, install_dir, &self.app_handle)
{ {
error!("failed to mark game as completed: {}", error); error!("failed to mark game as completed: {}", error);
// TODO mark game as remote so user can retry // TODO mark game as remote so user can retry
@@ -359,13 +364,13 @@ impl DownloadManagerBuilder {
if let Some(download_agent) = self.download_agent_registry.get(&id) { if let Some(download_agent) = self.download_agent_registry.get(&id) {
let download_agent_handle = download_agent.lock().unwrap(); let download_agent_handle = download_agent.lock().unwrap();
if download_agent_handle.version() == version { if download_agent_handle.version() == version {
info!("game with same version already queued, skipping"); info!("Application with same version already queued, skipping");
return; return;
} }
// If it's not the same, we want to cancel the current one, and then add the new one // If it's not the same, we want to cancel the current one, and then add the new one
drop(download_agent_handle); drop(download_agent_handle);
self.manage_remove_game_queue(id.clone()); self.manage_remove_download_from_queue(id.clone());
} }
} }
@@ -377,8 +382,8 @@ impl DownloadManagerBuilder {
))); )));
let download_agent_lock = download_agent.lock().unwrap(); let download_agent_lock = download_agent.lock().unwrap();
let agent_status = GameDownloadStatus::Queued; let agent_status = DownloadStatus::Queued;
let interface_data = GameDownloadAgentQueueStandin { let interface_data = DownloadableQueueStandin {
id: id.clone(), id: id.clone(),
status: Mutex::new(agent_status), status: Mutex::new(agent_status),
progress: download_agent_lock.progress.clone(), progress: download_agent_lock.progress.clone(),
@@ -391,10 +396,10 @@ impl DownloadManagerBuilder {
.insert(interface_data.id.clone(), download_agent); .insert(interface_data.id.clone(), download_agent);
self.download_queue.append(interface_data); self.download_queue.append(interface_data);
self.set_game_status(id, |db, id| { self.set_download_status(id, |db, id| {
db.games.transient_statuses.insert( db.applications.transient_statuses.insert(
id.to_string(), id.to_string(),
GameTransientStatus::Downloading { version_name }, ApplicationTransientStatus::Downloading { version_name },
); );
}); });
self.sender self.sender
@@ -455,13 +460,13 @@ impl DownloadManagerBuilder {
drop(download_agent_lock); drop(download_agent_lock);
})); }));
// Set status for games // Set status for applications
for queue_game in self.download_queue.read() { for queue_application in self.download_queue.read() {
let mut status_handle = queue_game.status.lock().unwrap(); let mut status_handle = queue_application.status.lock().unwrap();
if queue_game.id == agent_data.id { if queue_application.id == agent_data.id {
*status_handle = GameDownloadStatus::Downloading; *status_handle = DownloadStatus::Downloading;
} else { } else {
*status_handle = GameDownloadStatus::Queued; *status_handle = DownloadStatus::Queued;
} }
drop(status_handle); drop(status_handle);
} }
@@ -469,10 +474,10 @@ impl DownloadManagerBuilder {
// Set flags for download manager // Set flags for download manager
active_control_flag.set(DownloadThreadControlFlag::Go); active_control_flag.set(DownloadThreadControlFlag::Go);
self.set_status(DownloadManagerStatus::Downloading); self.set_status(DownloadManagerStatus::Downloading);
self.set_game_status(agent_data.id.clone(), |db, id| { self.set_download_status(agent_data.id.clone(), |db, id| {
db.games.transient_statuses.insert( db.applications.transient_statuses.insert(
id.to_string(), id.to_string(),
GameTransientStatus::Downloading { version_name }, ApplicationTransientStatus::Downloading { version_name },
); );
}); });
@@ -485,19 +490,19 @@ impl DownloadManagerBuilder {
let current_status = self.current_download_agent.clone().unwrap(); let current_status = self.current_download_agent.clone().unwrap();
self.stop_and_wait_current_download(); self.stop_and_wait_current_download();
self.remove_and_cleanup_front_game(&current_status.id); // Remove all the locks and shit, and remove from queue self.remove_and_cleanup_front_download(&current_status.id); // Remove all the locks and shit, and remove from queue
self.app_handle self.app_handle
.emit("download_error", error.to_string()) .emit("download_error", error.to_string())
.unwrap(); .unwrap();
let mut lock = current_status.status.lock().unwrap(); let mut lock = current_status.status.lock().unwrap();
*lock = GameDownloadStatus::Error; *lock = DownloadStatus::Error;
self.set_status(DownloadManagerStatus::Error(error)); self.set_status(DownloadManagerStatus::Error(error));
let game_id = current_status.id.clone(); let id = current_status.id.clone();
self.set_game_status(game_id, |db_handle, id| { self.set_download_status(id, |db_handle, id| {
db_handle.games.transient_statuses.remove(id); db_handle.applications.transient_statuses.remove(id);
}); });
self.sender self.sender
+14 -14
View File
@@ -3,11 +3,11 @@ use std::{
sync::{Arc, Mutex, MutexGuard}, sync::{Arc, Mutex, MutexGuard},
}; };
use super::download_manager::GameDownloadAgentQueueStandin; use super::download_manager_builder::DownloadableQueueStandin;
#[derive(Clone)] #[derive(Clone)]
pub struct Queue { pub struct Queue {
inner: Arc<Mutex<VecDeque<Arc<GameDownloadAgentQueueStandin>>>>, inner: Arc<Mutex<VecDeque<Arc<DownloadableQueueStandin>>>>,
} }
#[allow(dead_code)] #[allow(dead_code)]
@@ -17,13 +17,13 @@ impl Queue {
inner: Arc::new(Mutex::new(VecDeque::new())), inner: Arc::new(Mutex::new(VecDeque::new())),
} }
} }
pub fn read(&self) -> VecDeque<Arc<GameDownloadAgentQueueStandin>> { pub fn read(&self) -> VecDeque<Arc<DownloadableQueueStandin>> {
self.inner.lock().unwrap().clone() self.inner.lock().unwrap().clone()
} }
pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<GameDownloadAgentQueueStandin>>> { pub fn edit(&self) -> MutexGuard<'_, VecDeque<Arc<DownloadableQueueStandin>>> {
self.inner.lock().unwrap() self.inner.lock().unwrap()
} }
pub fn pop_front(&self) -> Option<Arc<GameDownloadAgentQueueStandin>> { pub fn pop_front(&self) -> Option<Arc<DownloadableQueueStandin>> {
self.edit().pop_front() self.edit().pop_front()
} }
pub fn empty(&self) -> bool { pub fn empty(&self) -> bool {
@@ -31,35 +31,35 @@ impl Queue {
} }
/// Either inserts `interface` at the specified index, or appends to /// Either inserts `interface` at the specified index, or appends to
/// the back of the deque if index is greater than the length of the deque /// the back of the deque if index is greater than the length of the deque
pub fn insert(&self, interface: GameDownloadAgentQueueStandin, index: usize) { pub fn insert(&self, interface: DownloadableQueueStandin, index: usize) {
if self.read().len() > index { if self.read().len() > index {
self.append(interface); self.append(interface);
} else { } else {
self.edit().insert(index, Arc::new(interface)); self.edit().insert(index, Arc::new(interface));
} }
} }
pub fn append(&self, interface: GameDownloadAgentQueueStandin) { pub fn append(&self, interface: DownloadableQueueStandin) {
self.edit().push_back(Arc::new(interface)); self.edit().push_back(Arc::new(interface));
} }
pub fn pop_front_if_equal( pub fn pop_front_if_equal(
&self, &self,
game_id: String, id: String,
) -> Option<Arc<GameDownloadAgentQueueStandin>> { ) -> Option<Arc<DownloadableQueueStandin>> {
let mut queue = self.edit(); let mut queue = self.edit();
let front = match queue.front() { let front = match queue.front() {
Some(front) => front, Some(front) => front,
None => return None, None => return None,
}; };
if front.id == game_id { if front.id == id {
return queue.pop_front(); return queue.pop_front();
} }
None None
} }
pub fn get_by_id(&self, game_id: String) -> Option<usize> { pub fn get_by_id(&self, id: String) -> Option<usize> {
self.read().iter().position(|data| data.id == game_id) self.read().iter().position(|data| data.id == id)
} }
pub fn move_to_index_by_id(&self, game_id: String, new_index: usize) -> Result<(), ()> { pub fn move_to_index_by_id(&self, id: String, new_index: usize) -> Result<(), ()> {
let index = match self.get_by_id(game_id) { let index = match self.get_by_id(id) {
Some(index) => index, Some(index) => index,
None => return Err(()), None => return Err(()),
}; };
@@ -1,6 +1,6 @@
use crate::auth::generate_authorization_header; use crate::auth::generate_authorization_header;
use crate::db::DatabaseImpls; use crate::db::DatabaseImpls;
use crate::download_manager::download_manager::{DownloadManagerSignal, GameDownloadStatus}; use crate::download_manager::download_manager::{DownloadManagerSignal, DownloadStatus};
use crate::download_manager::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}; use crate::download_manager::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
use crate::download_manager::downloadable::Downloadable; use crate::download_manager::downloadable::Downloadable;
use crate::download_manager::progress_object::{ProgressHandle, ProgressObject}; use crate::download_manager::progress_object::{ProgressHandle, ProgressObject};
@@ -35,9 +35,9 @@ pub struct GameDownloadAgent {
pub progress: Arc<ProgressObject>, pub progress: Arc<ProgressObject>,
sender: Sender<DownloadManagerSignal>, sender: Sender<DownloadManagerSignal>,
pub stored_manifest: StoredManifest, pub stored_manifest: StoredManifest,
status: Mutex<GameDownloadStatus>
} }
// TODO: Rename / separate from downloads
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum GameDownloadError { pub enum GameDownloadError {
Communication(RemoteAccessError), Communication(RemoteAccessError),
@@ -85,7 +85,7 @@ impl GameDownloadAgent {
let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop); let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop);
let db_lock = DB.borrow_data().unwrap(); let db_lock = DB.borrow_data().unwrap();
let base_dir = db_lock.games.install_dirs[target_download_dir].clone(); let base_dir = db_lock.applications.install_dirs[target_download_dir].clone();
drop(db_lock); drop(db_lock);
let base_dir_path = Path::new(&base_dir); let base_dir_path = Path::new(&base_dir);
@@ -104,7 +104,6 @@ impl GameDownloadAgent {
progress: Arc::new(ProgressObject::new(0, 0, sender.clone())), progress: Arc::new(ProgressObject::new(0, 0, sender.clone())),
sender, sender,
stored_manifest, stored_manifest,
status: Mutex::new(GameDownloadStatus::Queued),
} }
} }
@@ -13,7 +13,7 @@ pub fn download_game(
.lock() .lock()
.unwrap() .unwrap()
.download_manager .download_manager
.queue_game(game_id, game_version, install_dir) .queue_download(game_id, game_version, install_dir)
.map_err(|_| "An error occurred while communicating with the download manager.".to_string()) .map_err(|_| "An error occurred while communicating with the download manager.".to_string())
} }
+7 -7
View File
@@ -22,7 +22,7 @@ use auth::{
}; };
use cleanup::{cleanup_and_exit, quit}; use cleanup::{cleanup_and_exit, quit};
use db::{ use db::{
add_download_dir, delete_download_dir, fetch_download_dir_stats, DatabaseInterface, GameStatus, add_download_dir, delete_download_dir, fetch_download_dir_stats, DatabaseInterface, ApplicationStatus,
DATA_ROOT_DIR, DATA_ROOT_DIR,
}; };
use download_manager::download_manager::DownloadManager; use download_manager::download_manager::DownloadManager;
@@ -148,12 +148,12 @@ fn setup(handle: AppHandle) -> AppState<'static> {
let db_handle = DB.borrow_data().unwrap(); let db_handle = DB.borrow_data().unwrap();
let mut missing_games = Vec::new(); let mut missing_games = Vec::new();
let statuses = db_handle.games.statuses.clone(); let statuses = db_handle.applications.statuses.clone();
drop(db_handle); drop(db_handle);
for (game_id, status) in statuses.into_iter() { for (game_id, status) in statuses.into_iter() {
match status { match status {
db::GameStatus::Remote {} => {} db::ApplicationStatus::Remote {} => {}
db::GameStatus::SetupRequired { db::ApplicationStatus::SetupRequired {
version_name: _, version_name: _,
install_dir, install_dir,
} => { } => {
@@ -162,7 +162,7 @@ fn setup(handle: AppHandle) -> AppState<'static> {
missing_games.push(game_id); missing_games.push(game_id);
} }
} }
db::GameStatus::Installed { db::ApplicationStatus::Installed {
version_name: _, version_name: _,
install_dir, install_dir,
} => { } => {
@@ -179,10 +179,10 @@ fn setup(handle: AppHandle) -> AppState<'static> {
let mut db_handle = DB.borrow_data_mut().unwrap(); let mut db_handle = DB.borrow_data_mut().unwrap();
for game_id in missing_games { for game_id in missing_games {
db_handle db_handle
.games .applications
.statuses .statuses
.entry(game_id.to_string()) .entry(game_id.to_string())
.and_modify(|v| *v = GameStatus::Remote {}); .and_modify(|v| *v = ApplicationStatus::Remote {});
} }
drop(db_handle); drop(db_handle);
info!("finished setup!"); info!("finished setup!");
+16 -16
View File
@@ -7,9 +7,9 @@ use tauri::{AppHandle, Manager};
use urlencoding::encode; use urlencoding::encode;
use crate::db::DatabaseImpls; use crate::db::DatabaseImpls;
use crate::db::GameStatus; use crate::db::ApplicationVersion;
use crate::db::GameVersion; use crate::db::ApplicationStatus;
use crate::downloads::download_manager::{DownloadManagerStatus, GameDownloadStatus}; use crate::download_manager::download_manager::{DownloadManagerStatus, DownloadStatus};
use crate::process::process_manager::Platform; use crate::process::process_manager::Platform;
use crate::remote::{DropServerError, RemoteAccessError}; use crate::remote::{DropServerError, RemoteAccessError};
use crate::state::{GameStatusManager, GameStatusWithTransient}; use crate::state::{GameStatusManager, GameStatusWithTransient};
@@ -44,7 +44,7 @@ pub struct GameUpdateEvent {
#[derive(Serialize, Clone)] #[derive(Serialize, Clone)]
pub struct QueueUpdateEventQueueData { pub struct QueueUpdateEventQueueData {
pub id: String, pub id: String,
pub status: GameDownloadStatus, pub status: DownloadStatus,
pub progress: f64, pub progress: f64,
} }
@@ -99,11 +99,11 @@ fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
for game in games.iter() { for game in games.iter() {
handle.games.insert(game.id.clone(), game.clone()); handle.games.insert(game.id.clone(), game.clone());
if !db_handle.games.statuses.contains_key(&game.id) { if !db_handle.applications.statuses.contains_key(&game.id) {
db_handle db_handle
.games .applications
.statuses .statuses
.insert(game.id.clone(), GameStatus::Remote {}); .insert(game.id.clone(), ApplicationStatus::Remote {});
} }
} }
@@ -162,10 +162,10 @@ fn fetch_game_logic(
let mut db_handle = DB.borrow_data_mut().unwrap(); let mut db_handle = DB.borrow_data_mut().unwrap();
db_handle db_handle
.games .applications
.statuses .statuses
.entry(id.clone()) .entry(id.clone())
.or_insert(GameStatus::Remote {}); .or_insert(ApplicationStatus::Remote {});
drop(db_handle); drop(db_handle);
let status = GameStatusManager::fetch_state(&id); let status = GameStatusManager::fetch_state(&id);
@@ -246,13 +246,13 @@ pub fn uninstall_game(
state: tauri::State<'_, Mutex<AppState>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<(), String> { ) -> Result<(), String> {
let state_lock = state.lock().unwrap(); let state_lock = state.lock().unwrap();
state_lock.download_manager.uninstall_game(game_id); state_lock.download_manager.uninstall_application(game_id);
drop(state_lock); drop(state_lock);
Ok(()) Ok(())
} }
pub fn push_game_update(app_handle: &AppHandle, id: String, status: GameStatusWithTransient) { pub fn push_application_update(app_handle: &AppHandle, id: String, status: GameStatusWithTransient) {
app_handle app_handle
.emit( .emit(
&format!("update_game/{}", id), &format!("update_game/{}", id),
@@ -297,11 +297,11 @@ pub fn on_game_complete(
)); ));
} }
let data = response.json::<GameVersion>()?; let data = response.json::<ApplicationVersion>()?;
let mut handle = DB.borrow_data_mut().unwrap(); let mut handle = DB.borrow_data_mut().unwrap();
handle handle
.games .applications
.versions .versions
.entry(game_id.clone()) .entry(game_id.clone())
.or_default() .or_default()
@@ -310,12 +310,12 @@ pub fn on_game_complete(
DB.save().unwrap(); DB.save().unwrap();
let status = if data.setup_command.is_empty() { let status = if data.setup_command.is_empty() {
GameStatus::Installed { ApplicationStatus::Installed {
version_name, version_name,
install_dir, install_dir,
} }
} else { } else {
GameStatus::SetupRequired { ApplicationStatus::SetupRequired {
version_name, version_name,
install_dir, install_dir,
} }
@@ -323,7 +323,7 @@ pub fn on_game_complete(
let mut db_handle = DB.borrow_data_mut().unwrap(); let mut db_handle = DB.borrow_data_mut().unwrap();
db_handle db_handle
.games .applications
.statuses .statuses
.insert(game_id.clone(), status.clone()); .insert(game_id.clone(), status.clone());
drop(db_handle); drop(db_handle);
@@ -15,8 +15,8 @@ use tauri::{AppHandle, Manager};
use umu_wrapper_lib::command_builder::UmuCommandBuilder; use umu_wrapper_lib::command_builder::UmuCommandBuilder;
use crate::{ use crate::{
db::{GameStatus, GameTransientStatus, DATA_ROOT_DIR}, db::{ApplicationStatus, ApplicationTransientStatus, DATA_ROOT_DIR},
library::push_game_update, library::push_application_update,
state::GameStatusManager, state::GameStatusManager,
AppState, DB, AppState, DB,
}; };
@@ -107,20 +107,20 @@ impl ProcessManager<'_> {
self.processes.remove(&game_id); self.processes.remove(&game_id);
let mut db_handle = DB.borrow_data_mut().unwrap(); let mut db_handle = DB.borrow_data_mut().unwrap();
db_handle.games.transient_statuses.remove(&game_id); db_handle.applications.transient_statuses.remove(&game_id);
let current_state = db_handle.games.statuses.get(&game_id).cloned(); let current_state = db_handle.applications.statuses.get(&game_id).cloned();
if let Some(saved_state) = current_state { if let Some(saved_state) = current_state {
if let GameStatus::SetupRequired { if let ApplicationStatus::SetupRequired {
version_name, version_name,
install_dir, install_dir,
} = saved_state } = saved_state
{ {
if let Ok(exit_code) = result { if let Ok(exit_code) = result {
if exit_code.success() { if exit_code.success() {
db_handle.games.statuses.insert( db_handle.applications.statuses.insert(
game_id.clone(), game_id.clone(),
GameStatus::Installed { ApplicationStatus::Installed {
version_name: version_name.to_string(), version_name: version_name.to_string(),
install_dir: install_dir.to_string(), install_dir: install_dir.to_string(),
}, },
@@ -133,7 +133,7 @@ impl ProcessManager<'_> {
let status = GameStatusManager::fetch_state(&game_id); let status = GameStatusManager::fetch_state(&game_id);
push_game_update(&self.app_handle, game_id.clone(), status); push_application_update(&self.app_handle, game_id.clone(), status);
// TODO better management // TODO better management
} }
@@ -152,17 +152,17 @@ impl ProcessManager<'_> {
let mut db_lock = DB.borrow_data_mut().unwrap(); let mut db_lock = DB.borrow_data_mut().unwrap();
let game_status = db_lock let game_status = db_lock
.games .applications
.statuses .statuses
.get(&game_id) .get(&game_id)
.ok_or("Game not installed")?; .ok_or("Game not installed")?;
let status_metadata: Option<(&String, &String)> = match game_status { let status_metadata: Option<(&String, &String)> = match game_status {
GameStatus::Installed { ApplicationStatus::Installed {
version_name, version_name,
install_dir, install_dir,
} => Some((version_name, install_dir)), } => Some((version_name, install_dir)),
GameStatus::SetupRequired { ApplicationStatus::SetupRequired {
version_name, version_name,
install_dir, install_dir,
} => Some((version_name, install_dir)), } => Some((version_name, install_dir)),
@@ -176,7 +176,7 @@ impl ProcessManager<'_> {
let (version_name, install_dir) = status_metadata.unwrap(); let (version_name, install_dir) = status_metadata.unwrap();
let game_version = db_lock let game_version = db_lock
.games .applications
.versions .versions
.get(&game_id) .get(&game_id)
.ok_or("Invalid game ID".to_owned())? .ok_or("Invalid game ID".to_owned())?
@@ -184,11 +184,11 @@ impl ProcessManager<'_> {
.ok_or("Invalid version name".to_owned())?; .ok_or("Invalid version name".to_owned())?;
let raw_command: String = match game_status { let raw_command: String = match game_status {
GameStatus::Installed { ApplicationStatus::Installed {
version_name: _, version_name: _,
install_dir: _, install_dir: _,
} => game_version.launch_command.clone(), } => game_version.launch_command.clone(),
GameStatus::SetupRequired { ApplicationStatus::SetupRequired {
version_name: _, version_name: _,
install_dir: _, install_dir: _,
} => game_version.setup_command.clone(), } => game_version.setup_command.clone(),
@@ -252,14 +252,14 @@ impl ProcessManager<'_> {
Arc::new(SharedChild::new(launch_process).map_err(|e| e.to_string())?); Arc::new(SharedChild::new(launch_process).map_err(|e| e.to_string())?);
db_lock db_lock
.games .applications
.transient_statuses .transient_statuses
.insert(game_id.clone(), GameTransientStatus::Running {}); .insert(game_id.clone(), ApplicationTransientStatus::Running {});
push_game_update( push_application_update(
&self.app_handle, &self.app_handle,
game_id.clone(), game_id.clone(),
(None, Some(GameTransientStatus::Running {})), (None, Some(ApplicationTransientStatus::Running {})),
); );
let wait_thread_handle = launch_process_handle.clone(); let wait_thread_handle = launch_process_handle.clone();
+4 -4
View File
@@ -1,9 +1,9 @@
use crate::{ use crate::{
db::{Database, GameStatus, GameTransientStatus}, db::{ApplicationStatus, ApplicationTransientStatus, Database},
DB, DB,
}; };
pub type GameStatusWithTransient = (Option<GameStatus>, Option<GameTransientStatus>); pub type GameStatusWithTransient = (Option<ApplicationStatus>, Option<ApplicationTransientStatus>);
pub struct GameStatusManager {} pub struct GameStatusManager {}
impl GameStatusManager { impl GameStatusManager {
@@ -15,8 +15,8 @@ impl GameStatusManager {
game_id: &String, game_id: &String,
db_lock: &Database, db_lock: &Database,
) -> GameStatusWithTransient { ) -> GameStatusWithTransient {
let offline_state = db_lock.games.statuses.get(game_id).cloned(); let offline_state = db_lock.applications.statuses.get(game_id).cloned();
let online_state = db_lock.games.transient_statuses.get(game_id).cloned(); let online_state = db_lock.applications.transient_statuses.get(game_id).cloned();
if online_state.is_some() { if online_state.is_some() {
return (None, online_state); return (None, online_state);