diff --git a/app.vue b/app.vue index b921045..fb5f882 100644 --- a/app.vue +++ b/app.vue @@ -20,10 +20,10 @@ import { const router = useRouter(); const state = useAppState(); -state.value = await invoke("fetch_state"); +state.value = JSON.parse(await invoke("fetch_state")); router.beforeEach(async () => { - state.value = await invoke("fetch_state"); + state.value = JSON.parse(await invoke("fetch_state")); }); setupHooks(); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6e6dcf5..8ad9c33 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -3,12 +3,12 @@ mod db; mod downloads; mod library; +mod cleanup; mod process; mod remote; mod state; #[cfg(test)] mod tests; -mod cleanup; use crate::db::DatabaseImpls; use auth::{auth_initiate, generate_authorization_header, recieve_handshake, retry_connect}; @@ -65,7 +65,7 @@ pub struct User { #[derive(Clone, Serialize)] #[serde(rename_all = "camelCase")] -pub struct AppState { +pub struct AppState<'a> { status: AppStatus, user: Option, games: HashMap, @@ -73,18 +73,18 @@ pub struct AppState { #[serde(skip_serializing)] download_manager: Arc, #[serde(skip_serializing)] - process_manager: Arc>, + process_manager: Arc>>, } #[tauri::command] -fn fetch_state(state: tauri::State<'_, Mutex>) -> Result { +fn fetch_state(state: tauri::State<'_, Mutex>>) -> Result { let guard = state.lock().unwrap(); - let cloned_state = guard.clone(); + let cloned_state = serde_json::to_string(&guard.clone()).map_err(|e| e.to_string())?; drop(guard); Ok(cloned_state) } -fn setup(handle: AppHandle) -> AppState { +fn setup(handle: AppHandle) -> AppState<'static> { let logfile = FileAppender::builder() .encoder(Box::new(PatternEncoder::new("{d} | {l} | {f} - {m}{n}"))) .append(false) @@ -137,7 +137,6 @@ fn setup(handle: AppHandle) -> AppState { } } - pub static DB: LazyLock = LazyLock::new(DatabaseInterface::set_up_database); #[cfg_attr(mobile, tauri::mobile_entry_point)] diff --git a/src-tauri/src/process/process_manager.rs b/src-tauri/src/process/process_manager.rs index 5266849..a26904c 100644 --- a/src-tauri/src/process/process_manager.rs +++ b/src-tauri/src/process/process_manager.rs @@ -1,7 +1,6 @@ use std::{ collections::HashMap, fs::{File, OpenOptions}, - io::{Stdout, Write}, path::{Path, PathBuf}, process::{Child, Command}, sync::LazyLock, @@ -15,13 +14,14 @@ use crate::{ DB, }; -pub struct ProcessManager { +pub struct ProcessManager<'a> { current_platform: Platform, log_output_dir: PathBuf, processes: HashMap, + game_launchers: HashMap<(Platform, Platform), &'a (dyn ProcessHandler + Sync + Send + 'static)>, } -impl ProcessManager { +impl ProcessManager<'_> { pub fn new() -> Self { let root_dir_lock = DATA_ROOT_DIR.lock().unwrap(); let log_output_dir = root_dir_lock.join("logs"); @@ -36,6 +36,17 @@ impl ProcessManager { processes: HashMap::new(), log_output_dir, + game_launchers: HashMap::from([ + // Current platform to target platform + ( + (Platform::Windows, Platform::Windows), + &NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static), + ), + ( + (Platform::Linux, Platform::Linux), + &NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static), + ), + ]), } } @@ -55,11 +66,15 @@ impl ProcessManager { pub fn valid_platform(&self, platform: &Platform) -> Result { let current = &self.current_platform; - let valid_platforms = PROCESS_COMPATABILITY_MATRIX - .get(current) - .ok_or("Incomplete platform compatability matrix.")?; - - Ok(valid_platforms.contains(platform)) + info!("{:?}", self.game_launchers.keys()); + info!( + "{:?} {}", + (current.clone(), platform.clone()), + (Platform::Linux, Platform::Linux) == (Platform::Linux, Platform::Linux) + ); + Ok(self + .game_launchers + .contains_key(&(current.clone(), platform.clone()))) } pub fn launch_game(&mut self, game_id: String) -> Result<(), String> { @@ -112,21 +127,33 @@ impl ProcessManager { .truncate(true) .read(true) .create(true) - .open( - self.log_output_dir - .join(format!("{}-{}-error.log", game_id, current_time.timestamp())), - ) + .open(self.log_output_dir.join(format!( + "{}-{}-error.log", + game_id, + current_time.timestamp() + ))) .map_err(|v| v.to_string())?; info!("opened log file for {}", command); - let launch_process = Command::new(command) - .current_dir(install_dir) - .stdout(log_file) - .stderr(error_file) - .args(args) - .spawn() - .map_err(|v| v.to_string())?; + let current_platform = self.current_platform.clone(); + let target_platform = game_version.platform.clone(); + + let game_launcher = self + .game_launchers + .get(&(current_platform, target_platform)) + .ok_or("Invalid version for this platform.") + .map_err(|e| e.to_string())?; + + let launch_process = game_launcher.launch_game( + &game_id, + version_name, + command, + args, + install_dir, + log_file, + error_file, + )?; self.processes.insert(game_id, launch_process); @@ -134,19 +161,43 @@ impl ProcessManager { } } -#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Clone)] +#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Clone, Debug)] pub enum Platform { Windows, Linux, } -pub type ProcessCompatabilityMatrix = HashMap>; -pub static PROCESS_COMPATABILITY_MATRIX: LazyLock = - LazyLock::new(|| { - let mut matrix: ProcessCompatabilityMatrix = HashMap::new(); +pub trait ProcessHandler: Send + 'static { + fn launch_game( + &self, + game_id: &String, + version_name: &String, + command: String, + args: Vec, + install_dir: &String, + log_file: File, + error_file: File, + ) -> Result; +} - matrix.insert(Platform::Windows, vec![Platform::Windows]); - matrix.insert(Platform::Linux, vec![Platform::Linux]); // TODO: add Proton support - - return matrix; - }); +struct NativeGameLauncher; +impl ProcessHandler for NativeGameLauncher { + fn launch_game( + &self, + game_id: &String, + version_name: &String, + command: String, + args: Vec, + install_dir: &String, + log_file: File, + error_file: File, + ) -> Result { + Command::new(command) + .current_dir(install_dir) + .stdout(log_file) + .stderr(error_file) + .args(args) + .spawn() + .map_err(|v| v.to_string()) + } +} diff --git a/src-tauri/src/remote.rs b/src-tauri/src/remote.rs index 33655c2..a70a748 100644 --- a/src-tauri/src/remote.rs +++ b/src-tauri/src/remote.rs @@ -71,7 +71,7 @@ struct DropHealthcheck { async fn use_remote_logic<'a>( url: String, - state: tauri::State<'_, Mutex>, + state: tauri::State<'_, Mutex>>, ) -> Result<(), RemoteAccessError> { info!("connecting to url {}", url); let base_url = Url::parse(&url)?; @@ -103,7 +103,7 @@ async fn use_remote_logic<'a>( #[tauri::command] pub async fn use_remote<'a>( url: String, - state: tauri::State<'_, Mutex>, + state: tauri::State<'_, Mutex>>, ) -> Result<(), String> { let result = use_remote_logic(url, state).await;