From c2d8966c1a93254b5285618046dc873f9d563cc6 Mon Sep 17 00:00:00 2001 From: quexeky <116044207+quexeky@users.noreply.github.com> Date: Mon, 20 Jan 2025 08:22:42 +1100 Subject: [PATCH] feat(database): Ensure that any database issues are resolved by standalone functions Functions are as follows: - save_db() - borrow_db_checked() - borrow_db_mut_checked() --- desktop/src-tauri/src/autostart.rs | 10 ++--- desktop/src-tauri/src/database/commands.rs | 20 +++++----- desktop/src-tauri/src/database/db.rs | 39 +++++++++++++++++-- .../download_manager_builder.rs | 3 +- .../src/games/downloads/download_agent.rs | 6 +-- desktop/src-tauri/src/games/library.rs | 23 ++++++----- desktop/src-tauri/src/games/state.rs | 4 +- desktop/src-tauri/src/lib.rs | 8 ++-- .../src-tauri/src/process/process_manager.rs | 6 +-- desktop/src-tauri/src/remote/auth.rs | 14 +++---- desktop/src-tauri/src/remote/commands.rs | 9 ++--- desktop/src-tauri/src/remote/remote.rs | 6 +-- 12 files changed, 88 insertions(+), 60 deletions(-) diff --git a/desktop/src-tauri/src/autostart.rs b/desktop/src-tauri/src/autostart.rs index 6a4255c2..dec91489 100644 --- a/desktop/src-tauri/src/autostart.rs +++ b/desktop/src-tauri/src/autostart.rs @@ -1,4 +1,4 @@ -use crate::DB; +use crate::database::db::{borrow_db_checked, borrow_db_mut_checked, save_db}; use log::debug; use tauri::AppHandle; use tauri_plugin_autostart::ManagerExt; @@ -14,17 +14,17 @@ pub fn toggle_autostart_logic(app: AppHandle, enabled: bool) -> Result<(), Strin } // Store the state in DB - let mut db_handle = DB.borrow_data_mut().map_err(|e| e.to_string())?; + let mut db_handle = borrow_db_mut_checked(); db_handle.settings.autostart = enabled; drop(db_handle); - DB.save().map_err(|e| e.to_string())?; + save_db(); Ok(()) } pub fn get_autostart_enabled_logic(app: AppHandle) -> Result { // First check DB state - let db_handle = DB.borrow_data().unwrap(); + let db_handle = borrow_db_checked(); let db_state = db_handle.settings.autostart; drop(db_handle); @@ -46,7 +46,7 @@ pub fn get_autostart_enabled_logic(app: AppHandle) -> Result Result<(), String> { - let db_handle = DB.borrow_data().map_err(|e| e.to_string())?; + let db_handle = borrow_db_checked(); let should_be_enabled = db_handle.settings.autostart; drop(db_handle); diff --git a/desktop/src-tauri/src/database/commands.rs b/desktop/src-tauri/src/database/commands.rs index 00c1c48a..b3f64922 100644 --- a/desktop/src-tauri/src/database/commands.rs +++ b/desktop/src-tauri/src/database/commands.rs @@ -6,24 +6,24 @@ use std::{ use serde_json::Value; -use crate::{database::settings::Settings, download_manager::{download_manager::DownloadManagerSignal, internal_error::InternalError}, DB}; +use crate::{database::{db::borrow_db_mut_checked, settings::Settings}, download_manager::{download_manager::DownloadManagerSignal, internal_error::InternalError}, DB}; -use super::{db::DATA_ROOT_DIR, debug::SystemData}; +use super::{db::{borrow_db_checked, save_db, DATA_ROOT_DIR}, debug::SystemData}; // Will, in future, return disk/remaining size // Just returns the directories that have been set up #[tauri::command] pub fn fetch_download_dir_stats() -> Vec { - let lock = DB.borrow_data().unwrap(); + let lock = borrow_db_checked(); lock.applications.install_dirs.clone() } #[tauri::command] pub fn delete_download_dir(index: usize) { - let mut lock = DB.borrow_data_mut().unwrap(); + let mut lock = borrow_db_mut_checked(); lock.applications.install_dirs.remove(index); drop(lock); - DB.save().unwrap(); + save_db(); } #[tauri::command] @@ -43,7 +43,7 @@ pub fn add_download_dir(new_dir: PathBuf) -> Result<(), InternalError<()>> { } // Add it to the dictionary - let mut lock = DB.borrow_data_mut().unwrap(); + let mut lock = borrow_db_mut_checked(); if lock.applications.install_dirs.contains(&new_dir) { return Err(Error::new( ErrorKind::AlreadyExists, @@ -52,14 +52,14 @@ pub fn add_download_dir(new_dir: PathBuf) -> Result<(), InternalError<()>> { } lock.applications.install_dirs.push(new_dir); drop(lock); - DB.save().unwrap(); + save_db(); Ok(()) } #[tauri::command] pub fn update_settings(new_settings: Value) { - let mut db_lock = DB.borrow_data_mut().unwrap(); + let mut db_lock = borrow_db_mut_checked(); let mut current_settings = serde_json::to_value(db_lock.settings.clone()).unwrap(); for (key, value) in new_settings.as_object().unwrap() { current_settings[key] = value.clone(); @@ -70,11 +70,11 @@ pub fn update_settings(new_settings: Value) { } #[tauri::command] pub fn fetch_settings() -> Settings { - DB.borrow_data().unwrap().settings.clone() + borrow_db_checked().settings.clone() } #[tauri::command] pub fn fetch_system_data() -> SystemData { - let db_handle = DB.borrow_data().unwrap(); + let db_handle = borrow_db_checked(); SystemData::new( db_handle.auth.as_ref().unwrap().client_id.clone(), db_handle.base_url.clone(), diff --git a/desktop/src-tauri/src/database/db.rs b/desktop/src-tauri/src/database/db.rs index 82a2e444..6a3438a8 100644 --- a/desktop/src-tauri/src/database/db.rs +++ b/desktop/src-tauri/src/database/db.rs @@ -2,12 +2,12 @@ use std::{ collections::HashMap, fs::{self, create_dir_all}, path::{Path, PathBuf}, - sync::{LazyLock, Mutex, RwLockWriteGuard}, + sync::{LazyLock, Mutex, RwLockReadGuard, RwLockWriteGuard}, }; use chrono::Utc; use directories::BaseDirs; -use log::{debug, info}; +use log::{debug, error, info}; use rustbreak::{DeSerError, DeSerializer, PathDatabase, RustbreakError}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_with::serde_as; @@ -169,10 +169,10 @@ pub fn set_game_status, &Downloada meta: DownloadableMetadata, setter: F, ) { - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); setter(&mut db_handle, &meta); drop(db_handle); - DB.save().unwrap(); + save_db(); let status = GameStatusManager::fetch_state(&meta.id); @@ -200,3 +200,34 @@ fn handle_invalid_database( PathDatabase::create_at_path(db_path, db).expect("Database could not be created") } + + +pub fn borrow_db_checked<'a>() -> RwLockReadGuard<'a, Database> { + match DB.borrow_data() { + Ok(data) => data, + Err(e) => { + error!("database borrow failed with error {}", e); + panic!("database borrow failed with error {}", e); + }, + } +} + +pub fn borrow_db_mut_checked<'a>() -> RwLockWriteGuard<'a, Database> { + match DB.borrow_data_mut() { + Ok(data) => data, + Err(e) => { + error!("database borrow mut failed with error {}", e); + panic!("database borrow mut failed with error {}", e); + } + } +} + +pub fn save_db() { + match DB.save() { + Ok(_) => {}, + Err(e) => { + error!("database failed to save with error {}", e); + panic!("database failed to save with error {}", e) + }, + } +} \ No newline at end of file diff --git a/desktop/src-tauri/src/download_manager/download_manager_builder.rs b/desktop/src-tauri/src/download_manager/download_manager_builder.rs index b87b6c70..7beec146 100644 --- a/desktop/src-tauri/src/download_manager/download_manager_builder.rs +++ b/desktop/src-tauri/src/download_manager/download_manager_builder.rs @@ -289,9 +289,8 @@ impl DownloadManagerBuilder { self.stop_and_wait_current_download(); self.remove_and_cleanup_front_download(¤t_agent.metadata()); - - self.set_status(DownloadManagerStatus::Error(error)); } + self.set_status(DownloadManagerStatus::Error(error)); } fn manage_cancel_signal(&mut self, meta: &DownloadableMetadata) { debug!("got signal Cancel"); diff --git a/desktop/src-tauri/src/games/downloads/download_agent.rs b/desktop/src-tauri/src/games/downloads/download_agent.rs index c22f83ad..6e8cc8d3 100644 --- a/desktop/src-tauri/src/games/downloads/download_agent.rs +++ b/desktop/src-tauri/src/games/downloads/download_agent.rs @@ -1,6 +1,6 @@ use crate::auth::generate_authorization_header; use crate::database::db::{ - set_game_status, ApplicationTransientStatus, DatabaseImpls, GameDownloadStatus, + borrow_db_checked, set_game_status, ApplicationTransientStatus, DatabaseImpls, GameDownloadStatus }; use crate::download_manager::download_manager::{DownloadManagerSignal, DownloadStatus}; use crate::download_manager::download_thread_control_flag::{ @@ -56,7 +56,7 @@ impl GameDownloadAgent { // Don't run by default let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop); - let db_lock = DB.borrow_data().unwrap(); + let db_lock = borrow_db_checked(); let base_dir = db_lock.applications.install_dirs[target_download_dir].clone(); drop(db_lock); @@ -243,7 +243,7 @@ impl GameDownloadAgent { // TODO: Change return value on Err pub fn run(&self) -> Result { - let max_download_threads = DB.borrow_data().unwrap().settings.max_download_threads; + let max_download_threads = borrow_db_checked().settings.max_download_threads; debug!( "downloading game: {} with {} threads", diff --git a/desktop/src-tauri/src/games/library.rs b/desktop/src-tauri/src/games/library.rs index 363b9995..e7b16133 100644 --- a/desktop/src-tauri/src/games/library.rs +++ b/desktop/src-tauri/src/games/library.rs @@ -8,7 +8,7 @@ use tauri::Emitter; use tauri::{AppHandle, Manager}; use urlencoding::encode; -use crate::database::db::GameVersion; +use crate::database::db::{borrow_db_checked, borrow_db_mut_checked, save_db, GameVersion}; use crate::database::db::{ApplicationTransientStatus, DatabaseImpls, GameDownloadStatus}; use crate::download_manager::download_manager::DownloadStatus; use crate::download_manager::downloadable_metadata::DownloadableMetadata; @@ -103,7 +103,7 @@ pub fn fetch_library_logic(app: AppHandle) -> Result, RemoteAccessErro let state = app.state::>(); let mut handle = state.lock().unwrap(); - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); for game in games.iter() { handle.games.insert(game.id.clone(), game.clone()); @@ -155,7 +155,7 @@ pub fn fetch_game_logic( let game: Game = response.json()?; state_handle.games.insert(id.clone(), game.clone()); - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); db_handle .applications @@ -206,7 +206,7 @@ pub fn fetch_game_verion_options_logic( pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle) { println!("triggered uninstall for agent"); - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); db_handle .applications .transient_statuses @@ -249,7 +249,7 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle) error!("{}", e); } Ok(_) => { - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); db_handle.applications.transient_statuses.remove(&meta); db_handle .applications @@ -257,7 +257,7 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle) .entry(meta.id.clone()) .and_modify(|e| *e = GameDownloadStatus::Remote {}); drop(db_handle); - DB.save().unwrap(); + save_db(); debug!("uninstalled game id {}", &meta.id); @@ -272,8 +272,7 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle) } pub fn get_current_meta(game_id: &String) -> Option { - DB.borrow_data() - .unwrap() + borrow_db_checked() .applications .installed_game_version .get(game_id) @@ -309,7 +308,7 @@ pub fn on_game_complete( let data: GameVersion = response.json()?; - let mut handle = DB.borrow_data_mut().unwrap(); + let mut handle = borrow_db_mut_checked(); handle .applications .game_versions @@ -322,7 +321,7 @@ pub fn on_game_complete( .insert(meta.id.clone(), meta.clone()); drop(handle); - DB.save().unwrap(); + save_db(); let status = if data.setup_command.is_empty() { GameDownloadStatus::Installed { @@ -336,13 +335,13 @@ pub fn on_game_complete( } }; - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); db_handle .applications .game_statuses .insert(meta.id.clone(), status.clone()); drop(db_handle); - DB.save().unwrap(); + save_db(); app_handle .emit( &format!("update_game/{}", meta.id), diff --git a/desktop/src-tauri/src/games/state.rs b/desktop/src-tauri/src/games/state.rs index 29287db0..948d5709 100644 --- a/desktop/src-tauri/src/games/state.rs +++ b/desktop/src-tauri/src/games/state.rs @@ -1,5 +1,5 @@ use crate::{ - database::db::{ApplicationTransientStatus, GameDownloadStatus}, + database::db::{borrow_db_checked, ApplicationTransientStatus, GameDownloadStatus}, DB, }; @@ -11,7 +11,7 @@ pub struct GameStatusManager {} impl GameStatusManager { pub fn fetch_state(game_id: &String) -> GameStatusWithTransient { - let db_lock = DB.borrow_data().unwrap(); + let db_lock = borrow_db_checked(); let online_state = match db_lock.applications.installed_game_version.get(game_id) { Some(meta) => db_lock.applications.transient_statuses.get(meta).cloned(), None => None, diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index 035f217a..d84d47f1 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -18,7 +18,7 @@ use commands::fetch_state; use database::commands::{ add_download_dir, delete_download_dir, fetch_download_dir_stats, fetch_system_data, fetch_settings, update_settings }; -use database::db::{DatabaseInterface, GameDownloadStatus, DATA_ROOT_DIR}; +use database::db::{borrow_db_checked, borrow_db_mut_checked, DatabaseInterface, GameDownloadStatus, DATA_ROOT_DIR}; use download_manager::commands::{ cancel_game, move_download_in_queue, pause_downloads, resume_downloads, }; @@ -138,7 +138,7 @@ fn setup(handle: AppHandle) -> AppState<'static> { // TODO: Account for possible failure let (app_status, user) = auth::setup(); - let db_handle = DB.borrow_data().unwrap(); + let db_handle = borrow_db_checked(); let mut missing_games = Vec::new(); let statuses = db_handle.applications.game_statuses.clone(); drop(db_handle); @@ -168,7 +168,7 @@ fn setup(handle: AppHandle) -> AppState<'static> { info!("detected games missing: {:?}", missing_games); - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); for game_id in missing_games { db_handle .applications @@ -327,7 +327,7 @@ pub fn run() { .expect("error while setting up tray menu"); { - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); if let Some(original) = db_handle.prev_database.take() { warn!( "Database corrupted. Original file at {}", diff --git a/desktop/src-tauri/src/process/process_manager.rs b/desktop/src-tauri/src/process/process_manager.rs index 33c84133..0ff482c8 100644 --- a/desktop/src-tauri/src/process/process_manager.rs +++ b/desktop/src-tauri/src/process/process_manager.rs @@ -15,7 +15,7 @@ use tauri::{AppHandle, Manager}; use umu_wrapper_lib::command_builder::UmuCommandBuilder; use crate::{ - database::db::{ApplicationTransientStatus, GameDownloadStatus, DATA_ROOT_DIR}, + database::db::{borrow_db_mut_checked, ApplicationTransientStatus, GameDownloadStatus, DATA_ROOT_DIR}, download_manager::downloadable_metadata::{DownloadType, DownloadableMetadata}, error::process_error::ProcessError, games::{library::push_game_update, state::GameStatusManager}, @@ -106,7 +106,7 @@ impl ProcessManager<'_> { self.processes.remove(&game_id); - let mut db_handle = DB.borrow_data_mut().unwrap(); + let mut db_handle = borrow_db_mut_checked(); let meta = db_handle .applications .installed_game_version @@ -176,7 +176,7 @@ impl ProcessManager<'_> { download_type: DownloadType::Game, }; - let mut db_lock = DB.borrow_data_mut().unwrap(); + let mut db_lock = borrow_db_mut_checked(); debug!( "Launching process {:?} with games {:?}", &game_id, db_lock.applications.game_versions diff --git a/desktop/src-tauri/src/remote/auth.rs b/desktop/src-tauri/src/remote/auth.rs index 56cb89de..91839794 100644 --- a/desktop/src-tauri/src/remote/auth.rs +++ b/desktop/src-tauri/src/remote/auth.rs @@ -8,7 +8,7 @@ use tauri::{AppHandle, Emitter, Manager}; use url::Url; use crate::{ - database::db::{DatabaseAuth, DatabaseImpls}, + database::db::{borrow_db_checked, borrow_db_mut_checked, save_db, DatabaseAuth, DatabaseImpls}, error::{drop_server_error::DropServerError, remote_access_error::RemoteAccessError}, AppState, AppStatus, User, DB, }; @@ -51,7 +51,7 @@ pub fn sign_nonce(private_key: String, nonce: String) -> Result { pub fn generate_authorization_header() -> String { let certs = { - let db = DB.borrow_data().unwrap(); + let db = borrow_db_checked(); db.auth.clone().unwrap() }; @@ -97,7 +97,7 @@ fn recieve_handshake_logic(app: &AppHandle, path: String) -> Result<(), RemoteAc } let base_url = { - let handle = DB.borrow_data().unwrap(); + let handle = borrow_db_checked(); Url::parse(handle.base_url.as_str())? }; @@ -115,14 +115,14 @@ fn recieve_handshake_logic(app: &AppHandle, path: String) -> Result<(), RemoteAc let response_struct: HandshakeResponse = response.json()?; { - let mut handle = DB.borrow_data_mut().unwrap(); + let mut handle = borrow_db_mut_checked(); handle.auth = Some(DatabaseAuth { private: response_struct.private, cert: response_struct.certificate, client_id: response_struct.id, }); drop(handle); - DB.save().unwrap(); + save_db(); } { @@ -151,7 +151,7 @@ pub fn recieve_handshake(app: AppHandle, path: String) { pub fn auth_initiate_logic() -> Result<(), RemoteAccessError> { let base_url = { - let db_lock = DB.borrow_data().unwrap(); + let db_lock = borrow_db_checked(); Url::parse(&db_lock.base_url.clone())? }; @@ -181,7 +181,7 @@ pub fn auth_initiate_logic() -> Result<(), RemoteAccessError> { } pub fn setup() -> (AppStatus, Option) { - let data = DB.borrow_data().unwrap(); + let data = borrow_db_checked(); let auth = data.auth.clone(); drop(data); diff --git a/desktop/src-tauri/src/remote/commands.rs b/desktop/src-tauri/src/remote/commands.rs index 8daa5727..a6835943 100644 --- a/desktop/src-tauri/src/remote/commands.rs +++ b/desktop/src-tauri/src/remote/commands.rs @@ -4,8 +4,7 @@ use tauri::{AppHandle, Emitter, Manager}; use url::Url; use crate::{ - error::remote_access_error::RemoteAccessError, - AppState, AppStatus, DB, + database::db::{borrow_db_checked, borrow_db_mut_checked, save_db}, error::remote_access_error::RemoteAccessError, AppState, AppStatus, DB }; use super::{ @@ -24,7 +23,7 @@ pub fn use_remote( #[tauri::command] pub fn gen_drop_url(path: String) -> Result { let base_url = { - let handle = DB.borrow_data().unwrap(); + let handle = borrow_db_checked(); Url::parse(&handle.base_url).map_err(RemoteAccessError::ParsingError)? }; @@ -38,10 +37,10 @@ pub fn gen_drop_url(path: String) -> Result { pub fn sign_out(app: AppHandle) { // Clear auth from database { - let mut handle = DB.borrow_data_mut().unwrap(); + let mut handle = borrow_db_mut_checked(); handle.auth = None; drop(handle); - DB.save().unwrap(); + save_db(); } // Update app state diff --git a/desktop/src-tauri/src/remote/remote.rs b/desktop/src-tauri/src/remote/remote.rs index 0b10d4bf..64940e3b 100644 --- a/desktop/src-tauri/src/remote/remote.rs +++ b/desktop/src-tauri/src/remote/remote.rs @@ -9,7 +9,7 @@ use log::{debug, info, warn}; use serde::Deserialize; use url::{ParseError, Url}; -use crate::{error::remote_access_error::RemoteAccessError, AppState, AppStatus, DB}; +use crate::{database::db::{borrow_db_mut_checked, save_db}, error::remote_access_error::RemoteAccessError, AppState, AppStatus, DB}; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] @@ -39,11 +39,11 @@ pub fn use_remote_logic( app_state.status = AppStatus::SignedOut; drop(app_state); - let mut db_state = DB.borrow_data_mut().unwrap(); + let mut db_state = borrow_db_mut_checked(); db_state.base_url = base_url.to_string(); drop(db_state); - DB.save().unwrap(); + save_db(); Ok(()) }