From 5d22b883d5b0a40422a756f05ee4a5aa361f9938 Mon Sep 17 00:00:00 2001 From: quexeky Date: Sun, 12 Oct 2025 17:04:27 +1100 Subject: [PATCH] refactor: Improvements to src-tauri Signed-off-by: quexeky --- Cargo.lock | 1 + client/src/autostart.rs | 42 +------------ download_manager/src/frontend_updates.rs | 2 +- download_manager/src/lib.rs | 10 +++- games/src/library.rs | 11 ++++ process/src/process_manager.rs | 2 +- remote/src/cache.rs | 26 ++++---- remote/src/utils.rs | 8 ++- src-tauri/Cargo.toml | 5 +- src-tauri/src/client.rs | 41 ++++++++++++- src-tauri/src/error/download_manager_error.rs | 27 --------- src-tauri/src/error/mod.rs | 7 --- src-tauri/src/games.rs | 59 ++++++------------- src-tauri/src/lib.rs | 18 +++--- src-tauri/src/process.rs | 28 ++++----- src-tauri/src/remote.rs | 29 +++------ 16 files changed, 133 insertions(+), 183 deletions(-) delete mode 100644 src-tauri/src/error/download_manager_error.rs delete mode 100644 src-tauri/src/error/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 941aa57..53a60c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1380,6 +1380,7 @@ dependencies = [ "filetime", "futures-core", "futures-lite", + "games", "gethostname", "hex 0.4.3", "http 1.3.1", diff --git a/client/src/autostart.rs b/client/src/autostart.rs index 7ab6814..26b2efd 100644 --- a/client/src/autostart.rs +++ b/client/src/autostart.rs @@ -1,48 +1,8 @@ -use database::{borrow_db_checked, borrow_db_mut_checked}; +use database::borrow_db_checked; use log::debug; use tauri::AppHandle; use tauri_plugin_autostart::ManagerExt; -pub fn toggle_autostart_logic(app: AppHandle, enabled: bool) -> Result<(), String> { - let manager = app.autolaunch(); - if enabled { - manager.enable().map_err(|e| e.to_string())?; - debug!("enabled autostart"); - } else { - manager.disable().map_err(|e| e.to_string())?; - debug!("eisabled autostart"); - } - - // Store the state in DB - let mut db_handle = borrow_db_mut_checked(); - db_handle.settings.autostart = enabled; - drop(db_handle); - - Ok(()) -} - -pub fn get_autostart_enabled_logic(app: AppHandle) -> Result { - // First check DB state - let db_handle = borrow_db_checked(); - let db_state = db_handle.settings.autostart; - drop(db_handle); - - // Get actual system state - let manager = app.autolaunch(); - let system_state = manager.is_enabled()?; - - // If they don't match, sync to DB state - if db_state != system_state { - if db_state { - manager.enable()?; - } else { - manager.disable()?; - } - } - - Ok(db_state) -} - // New function to sync state on startup pub fn sync_autostart_on_startup(app: &AppHandle) -> Result<(), String> { let db_handle = borrow_db_checked(); diff --git a/download_manager/src/frontend_updates.rs b/download_manager/src/frontend_updates.rs index 62a6338..eb0a01b 100644 --- a/download_manager/src/frontend_updates.rs +++ b/download_manager/src/frontend_updates.rs @@ -17,7 +17,7 @@ pub struct QueueUpdateEvent { pub queue: Vec, } -#[derive(serde::Serialize, Clone)] +#[derive(Serialize, Clone)] pub struct StatsUpdateEvent { pub speed: usize, pub time: usize, diff --git a/download_manager/src/lib.rs b/download_manager/src/lib.rs index 0ac3b86..9a5de16 100644 --- a/download_manager/src/lib.rs +++ b/download_manager/src/lib.rs @@ -1,8 +1,16 @@ #![feature(duration_millis_float)] +#![feature(nonpoison_mutex)] +#![feature(sync_nonpoison)] + +use std::sync::{nonpoison::Mutex, LazyLock}; + +use crate::{download_manager_builder::DownloadManagerBuilder, download_manager_frontend::DownloadManager}; pub mod download_manager_builder; pub mod download_manager_frontend; pub mod downloadable; pub mod util; pub mod error; -pub mod frontend_updates; \ No newline at end of file +pub mod frontend_updates; + +pub static DOWNLOAD_MANAGER: LazyLock> = LazyLock::new(|| todo!()); \ No newline at end of file diff --git a/games/src/library.rs b/games/src/library.rs index 436d3f2..57d7fb5 100644 --- a/games/src/library.rs +++ b/games/src/library.rs @@ -18,6 +18,12 @@ pub struct FetchGameStruct { version: Option, } +impl FetchGameStruct { + pub fn new(game: Game, status: GameStatusWithTransient, version: Option) -> Self { + Self { game, status, version } + } +} + #[derive(Serialize, Deserialize, Clone, Debug, Default, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct Game { @@ -33,6 +39,11 @@ pub struct Game { m_image_library_object_ids: Vec, m_image_carousel_object_ids: Vec, } +impl Game { + pub fn id(&self) -> &String { + &self.id + } +} #[derive(serde::Serialize, Clone)] pub struct GameUpdateEvent { pub game_id: String, diff --git a/process/src/process_manager.rs b/process/src/process_manager.rs index 4897a4e..8fc1d4c 100644 --- a/process/src/process_manager.rs +++ b/process/src/process_manager.rs @@ -100,7 +100,7 @@ impl ProcessManager<'_> { } } - fn get_log_dir(&self, game_id: String) -> PathBuf { + pub fn get_log_dir(&self, game_id: String) -> PathBuf { self.log_output_dir.join(game_id) } diff --git a/remote/src/cache.rs b/remote/src/cache.rs index 974882a..d8e8b44 100644 --- a/remote/src/cache.rs +++ b/remote/src/cache.rs @@ -6,8 +6,8 @@ use std::{ }; use bitcode::{Decode, DecodeOwned, Encode}; -use database::{borrow_db_checked, Database}; -use http::{header::{CONTENT_TYPE}, response::Builder as ResponseBuilder, Response}; +use database::{Database, borrow_db_checked}; +use http::{Response, header::CONTENT_TYPE, response::Builder as ResponseBuilder}; use crate::error::{CacheError, RemoteAccessError}; @@ -15,7 +15,9 @@ use crate::error::{CacheError, RemoteAccessError}; macro_rules! offline { ($var:expr, $func1:expr, $func2:expr, $( $arg:expr ),* ) => { - async move { if $crate::borrow_db_checked().settings.force_offline || $crate::lock!($var).status == $crate::AppStatus::Offline { + async move { + if ::database::borrow_db_checked().settings.force_offline + || ::utils::lock!($var).status == ::client::app_status::AppStatus::Offline { $func2( $( $arg ), *).await } else { $func1( $( $arg ), *).await @@ -81,10 +83,7 @@ pub fn get_cached_object_db( pub fn clear_cached_object(key: &str) -> Result<(), RemoteAccessError> { clear_cached_object_db(key, &borrow_db_checked()) } -pub fn clear_cached_object_db( - key: &str, - db: &Database, -) -> Result<(), RemoteAccessError> { +pub fn clear_cached_object_db(key: &str, db: &Database) -> Result<(), RemoteAccessError> { delete_sync(&db.cache_dir, key).map_err(RemoteAccessError::Cache)?; Ok(()) } @@ -103,9 +102,9 @@ impl ObjectCache { } } -impl TryFrom>> for ObjectCache { +impl TryFrom>> for ObjectCache { type Error = CacheError; - + fn try_from(value: Response>) -> Result { Ok(ObjectCache { content_type: value @@ -118,14 +117,15 @@ impl TryFrom>> for ObjectCache { body: value.body().clone(), expiry: get_sys_time_in_secs() + 60 * 60 * 24, }) - } } impl TryFrom for Response> { type Error = CacheError; fn try_from(value: ObjectCache) -> Result { let resp_builder = ResponseBuilder::new().header(CONTENT_TYPE, value.content_type); - resp_builder.body(value.body).map_err(CacheError::ConstructionError) + resp_builder + .body(value.body) + .map_err(CacheError::ConstructionError) } } impl TryFrom<&ObjectCache> for Response> { @@ -133,6 +133,8 @@ impl TryFrom<&ObjectCache> for Response> { fn try_from(value: &ObjectCache) -> Result { let resp_builder = ResponseBuilder::new().header(CONTENT_TYPE, value.content_type.clone()); - resp_builder.body(value.body.clone()).map_err(CacheError::ConstructionError) + resp_builder + .body(value.body.clone()) + .map_err(CacheError::ConstructionError) } } diff --git a/remote/src/utils.rs b/remote/src/utils.rs index c8132cd..8b06893 100644 --- a/remote/src/utils.rs +++ b/remote/src/utils.rs @@ -11,10 +11,14 @@ use serde::Deserialize; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct DropHealthcheck { +pub struct DropHealthcheck { app_name: String, } - +impl DropHealthcheck { + pub fn app_name(&self) -> &String{ + &self.app_name + } +} static DROP_CERT_BUNDLE: LazyLock> = LazyLock::new(fetch_certificates); pub static DROP_CLIENT_SYNC: LazyLock = LazyLock::new(get_client_sync); pub static DROP_CLIENT_ASYNC: LazyLock = LazyLock::new(get_client_async); diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 826b69a..3402c9a 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -80,11 +80,12 @@ bytes = "1.10.1" # Workspaces -client = { path = "../client" } +client = { version = "0.1.0", path = "../client" } database = { path = "../database" } process = { path = "../process" } -remote = { path = "../remote" } +remote = { version = "0.1.0", path = "../remote" } utils = { path = "../utils" } +games = { version = "0.1.0", path = "../games" } [dependencies.dynfmt] version = "0.1.5" diff --git a/src-tauri/src/client.rs b/src-tauri/src/client.rs index f3dafd0..85a54a9 100644 --- a/src-tauri/src/client.rs +++ b/src-tauri/src/client.rs @@ -1,4 +1,10 @@ -use crate::{lock, AppState}; +use database::{borrow_db_checked, borrow_db_mut_checked}; +use log::{debug, error}; +use tauri::AppHandle; +use tauri_plugin_autostart::ManagerExt; +use utils::lock; + +use crate::{AppState}; #[tauri::command] pub fn fetch_state( @@ -31,10 +37,39 @@ pub fn cleanup_and_exit(app: &AppHandle, state: &tauri::State<'_, std::sync::Mut #[tauri::command] pub fn toggle_autostart(app: AppHandle, enabled: bool) -> Result<(), String> { - toggle_autostart_logic(app, enabled) + let manager = app.autolaunch(); + if enabled { + manager.enable().map_err(|e| e.to_string())?; + debug!("enabled autostart"); + } else { + manager.disable().map_err(|e| e.to_string())?; + debug!("eisabled autostart"); + } + + // Store the state in DB + let mut db_handle = borrow_db_mut_checked(); + db_handle.settings.autostart = enabled; + Ok(()) } #[tauri::command] pub fn get_autostart_enabled(app: AppHandle) -> Result { - get_autostart_enabled_logic(app) + let db_handle = borrow_db_checked(); + let db_state = db_handle.settings.autostart; + drop(db_handle); + + // Get actual system state + let manager = app.autolaunch(); + let system_state = manager.is_enabled()?; + + // If they don't match, sync to DB state + if db_state != system_state { + if db_state { + manager.enable()?; + } else { + manager.disable()?; + } + } + + Ok(db_state) } diff --git a/src-tauri/src/error/download_manager_error.rs b/src-tauri/src/error/download_manager_error.rs deleted file mode 100644 index b2ca365..0000000 --- a/src-tauri/src/error/download_manager_error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::{fmt::Display, io, sync::mpsc::SendError}; - -use serde_with::SerializeDisplay; - -#[derive(SerializeDisplay)] -pub enum DownloadManagerError { - IOError(io::Error), - SignalError(SendError), -} -impl Display for DownloadManagerError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DownloadManagerError::IOError(error) => write!(f, "{error}"), - DownloadManagerError::SignalError(send_error) => write!(f, "{send_error}"), - } - } -} -impl From> for DownloadManagerError { - fn from(value: SendError) -> Self { - DownloadManagerError::SignalError(value) - } -} -impl From for DownloadManagerError { - fn from(value: io::Error) -> Self { - DownloadManagerError::IOError(value) - } -} diff --git a/src-tauri/src/error/mod.rs b/src-tauri/src/error/mod.rs deleted file mode 100644 index 874837f..0000000 --- a/src-tauri/src/error/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod application_download_error; -pub mod download_manager_error; -pub mod drop_server_error; -pub mod library_error; -pub mod process_error; -pub mod remote_access_error; -pub mod cache_error; \ No newline at end of file diff --git a/src-tauri/src/games.rs b/src-tauri/src/games.rs index 3e2bea9..6548be7 100644 --- a/src-tauri/src/games.rs +++ b/src-tauri/src/games.rs @@ -1,28 +1,15 @@ use std::sync::Mutex; +use database::{borrow_db_checked, borrow_db_mut_checked, GameDownloadStatus, GameVersion}; +use games::{downloads::error::LibraryError, library::{get_current_meta, uninstall_game_logic, FetchGameStruct, Game}, state::{GameStatusManager, GameStatusWithTransient}}; +use log::warn; +use process::PROCESS_MANAGER; +use remote::{auth::generate_authorization_header, cache::{cache_object, cache_object_db, get_cached_object, get_cached_object_db}, error::{DropServerError, RemoteAccessError}, offline, requests::generate_url, utils::DROP_CLIENT_ASYNC}; use tauri::AppHandle; +use utils::lock; -use crate::{ - AppState, - database::{ - db::borrow_db_checked, - models::data::GameVersion, - }, - error::{library_error::LibraryError, remote_access_error::RemoteAccessError}, - games::library::{ - fetch_game_logic_offline, fetch_library_logic_offline, get_current_meta, - uninstall_game_logic, - }, - offline, -}; +use crate::AppState; -use super::{ - library::{ - FetchGameStruct, Game, fetch_game_logic, fetch_game_version_options_logic, - fetch_library_logic, - }, - state::{GameStatusManager, GameStatusWithTransient}, -}; #[tauri::command] pub async fn fetch_library( @@ -72,18 +59,18 @@ pub async fn fetch_library_logic( let mut db_handle = borrow_db_mut_checked(); for game in &games { - handle.games.insert(game.id.clone(), game.clone()); - if !db_handle.applications.game_statuses.contains_key(&game.id) { + handle.games.insert(game.id().clone(), game.clone()); + if !db_handle.applications.game_statuses.contains_key(game.id()) { db_handle .applications .game_statuses - .insert(game.id.clone(), GameDownloadStatus::Remote {}); + .insert(game.id().clone(), GameDownloadStatus::Remote {}); } } // Add games that are installed but no longer in library for meta in db_handle.applications.installed_game_version.values() { - if games.iter().any(|e| e.id == meta.id) { + if games.iter().any(|e| *e.id() == meta.id) { continue; } // We should always have a cache of the object @@ -120,7 +107,7 @@ pub async fn fetch_library_logic_offline( &db_handle .applications .game_statuses - .get(&game.id) + .get(game.id()) .unwrap_or(&GameDownloadStatus::Remote {}), GameDownloadStatus::Installed { .. } | GameDownloadStatus::SetupRequired { .. } ) @@ -152,11 +139,7 @@ pub async fn fetch_game_logic( if let Some(game) = game { let status = GameStatusManager::fetch_state(&id, &db_lock); - let data = FetchGameStruct { - game: game.clone(), - status, - version, - }; + let data = FetchGameStruct::new(game.clone(), status, version); cache_object_db(&id, game, &db_lock)?; @@ -205,11 +188,7 @@ pub async fn fetch_game_logic( drop(db_handle); - let data = FetchGameStruct { - game: game.clone(), - status, - version, - }; + let data = FetchGameStruct::new(game.clone(), status, version); cache_object(&id, &game)?; @@ -238,10 +217,10 @@ pub async fn fetch_game_version_options_logic( let data: Vec = response.json().await?; let state_lock = lock!(state); - let process_manager_lock = lock!(state_lock.process_manager); + let process_manager_lock = PROCESS_MANAGER.lock(); let data: Vec = data .into_iter() - .filter(|v| process_manager_lock.valid_platform(&v.platform, &state_lock)) + .filter(|v| process_manager_lock.valid_platform(&v.platform)) .collect(); drop(process_manager_lock); drop(state_lock); @@ -271,11 +250,7 @@ pub async fn fetch_game_logic_offline( drop(db_handle); - Ok(FetchGameStruct { - game, - status, - version, - }) + Ok(FetchGameStruct::new(game, status, version)) } #[tauri::command] diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index dca0983..03f403c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3,12 +3,21 @@ #![feature(duration_constructors)] #![feature(duration_millis_float)] #![feature(iterator_try_collect)] +#![feature(nonpoison_mutex)] #![deny(clippy::all)] +use std::collections::HashMap; + +use ::client::{app_status::AppStatus, compat::CompatInfo, user::User}; +use database::{borrow_db_checked, GameDownloadStatus}; +use ::games::library::Game; +use ::remote::auth; +use serde::Serialize; +use tauri::AppHandle; + mod games; mod client; -mod error; mod process; mod remote; @@ -19,13 +28,6 @@ pub struct AppState<'a> { status: AppStatus, user: Option, games: HashMap, - - #[serde(skip_serializing)] - download_manager: Arc, - #[serde(skip_serializing)] - process_manager: Arc>>, - #[serde(skip_serializing)] - compat_info: Option, } async fn setup(handle: AppHandle) -> AppState<'static> { diff --git a/src-tauri/src/process.rs b/src-tauri/src/process.rs index f2b9ce0..6bae1a4 100644 --- a/src-tauri/src/process.rs +++ b/src-tauri/src/process.rs @@ -1,6 +1,11 @@ use std::sync::Mutex; -use crate::{AppState, error::process_error::ProcessError, lock}; +use process::{error::ProcessError, PROCESS_MANAGER}; +use tauri::AppHandle; +use tauri_plugin_opener::OpenerExt; +use utils::lock; + +use crate::AppState; #[tauri::command] pub fn launch_game( @@ -8,8 +13,7 @@ pub fn launch_game( state: tauri::State<'_, Mutex>, ) -> Result<(), ProcessError> { let state_lock = lock!(state); - let mut process_manager_lock = lock!(state_lock.process_manager); - + let process_manager_lock = PROCESS_MANAGER.lock(); //let meta = DownloadableMetadata { // id, // version: Some(version), @@ -30,11 +34,9 @@ pub fn launch_game( #[tauri::command] pub fn kill_game( game_id: String, - state: tauri::State<'_, Mutex>, ) -> Result<(), ProcessError> { - let state_lock = lock!(state); - let mut process_manager_lock = lock!(state_lock.process_manager); - process_manager_lock + PROCESS_MANAGER + .lock() .kill_game(game_id) .map_err(ProcessError::IOError) } @@ -42,17 +44,13 @@ pub fn kill_game( #[tauri::command] pub fn open_process_logs( game_id: String, - state: tauri::State<'_, Mutex>, + app_handle: AppHandle ) -> Result<(), ProcessError> { - let state_lock = lock!(state); - let mut process_manager_lock = lock!(state_lock.process_manager); + let process_manager_lock = PROCESS_MANAGER.lock(); let dir = process_manager_lock.get_log_dir(game_id); - state - .handle() + app_handle .opener() .open_path(dir.display().to_string(), None::<&str>) - .map_err(ProcessError::OpenerError)?; - - process_manager_lock.open_process_logs(game_id) + .map_err(ProcessError::OpenerError) } diff --git a/src-tauri/src/remote.rs b/src-tauri/src/remote.rs index c5768e6..1d639cb 100644 --- a/src-tauri/src/remote.rs +++ b/src-tauri/src/remote.rs @@ -1,30 +1,17 @@ -use std::sync::Mutex; +use std::{sync::Mutex, time::Duration}; +use client::app_status::AppStatus; +use database::{borrow_db_checked, borrow_db_mut_checked}; use futures_lite::StreamExt; use log::{debug, warn}; +use remote::{auth::{auth_initiate_logic, generate_authorization_header}, cache::{cache_object, get_cached_object}, error::RemoteAccessError, requests::generate_url, setup, utils::{DropHealthcheck, DROP_CLIENT_ASYNC, DROP_CLIENT_WS_CLIENT}}; use reqwest_websocket::{Message, RequestBuilderExt}; use serde::Deserialize; use tauri::{AppHandle, Emitter, Manager}; use url::Url; +use utils::{app_emit, lock, webbrowser_open::webbrowser_open}; -use crate::{ - AppState, AppStatus, app_emit, - database::db::{borrow_db_checked, borrow_db_mut_checked}, - error::remote_access_error::RemoteAccessError, - lock, - remote::{ - auth::generate_authorization_header, - requests::generate_url, - utils::{DROP_CLIENT_SYNC, DROP_CLIENT_WS_CLIENT}, - }, - utils::webbrowser_open::webbrowser_open, -}; - -use super::{ - auth::{auth_initiate_logic, recieve_handshake, setup}, - cache::{cache_object, get_cached_object}, - utils::use_remote_logic, -}; +use crate::{recieve_handshake, AppState}; #[tauri::command] pub async fn use_remote( @@ -45,7 +32,7 @@ pub async fn use_remote( let result: DropHealthcheck = response.json().await?; - if result.app_name != "Drop" { + if result.app_name() != "Drop" { warn!("user entered drop endpoint that connected, but wasn't identified as Drop"); return Err(RemoteAccessError::InvalidEndpoint); } @@ -77,7 +64,7 @@ pub fn gen_drop_url(path: String) -> Result { pub fn fetch_drop_object(path: String) -> Result, RemoteAccessError> { let _drop_url = gen_drop_url(path.clone())?; let req = generate_url(&[&path], &[])?; - let req = DROP_CLIENT_SYNC + let req = remote::utils::DROP_CLIENT_SYNC .get(req) .header("Authorization", generate_authorization_header()) .send();