use log; use std::collections::HashMap; use tokio::sync::Mutex; use tokio::fs; use tauri::{AppHandle, Manager, State}; use crate::model::misc::Game; use crate::pkg::{Package, PkgKey}; use crate::pkg_store::InstallResult; use crate::profiles::ongeki::OngekiProfile; use crate::profiles::{self, AnyProfile, Profile, ProfileMeta, ProfilePaths}; use crate::appdata::AppData; use crate::util; #[tauri::command] pub async fn startline(app: AppHandle) -> Result<(), String> { log::debug!("invoke: startline"); let state = app.state::>(); let mut hash = "".to_owned(); let mut appd = state.lock().await; if let Some(p) = &appd.profile { hash = appd.sum_packages(p); } if let Some(p) = &mut appd.profile { log::debug!("{}", hash); p.line_up(hash, app.clone()).await .map_err(|e| format!("Lineup failed:\n{}", e))?; p.start(app.clone()).await .map_err(|e| format!("Startup failed:\n{}", e))?; Ok(()) } else { Err("No profile".to_owned()) } } #[tauri::command] pub async fn kill() -> Result<(), String> { util::pkill("amdaemon.exe").await; // The start routine will kill the other process Ok(()) } #[tauri::command] pub async fn install_package(state: State<'_, tokio::sync::Mutex>, key: PkgKey) -> Result { log::debug!("invoke: install_package({})", key); let mut appd = state.lock().await; appd.pkgs.install_package(&key, true, true) .await .map_err(|e| e.to_string()) } #[tauri::command] pub async fn delete_package(state: State<'_, tokio::sync::Mutex>, key: PkgKey) -> Result<(), String> { log::debug!("invoke: delete_package({})", key); let mut appd = state.lock().await; appd.pkgs.delete_package(&key, true) .await .map_err(|e| e.to_string()) } #[tauri::command] pub async fn get_package(state: State<'_, tokio::sync::Mutex>, key: PkgKey) -> Result { log::debug!("invoke: get_package({})", key); let appd = state.lock().await; appd.pkgs.get(&key) .map_err(|e| e.to_string()) .cloned() } #[tauri::command] pub async fn toggle_package(state: State<'_, tokio::sync::Mutex>, key: PkgKey, enable: bool) -> Result<(), String> { log::debug!("invoke: toggle_package({}, {})", key, enable); let mut appd = state.lock().await; appd.toggle_package(key, enable) .map_err(|e| e.to_string()) } #[tauri::command] pub async fn reload_all_packages(state: State<'_, tokio::sync::Mutex>) -> Result<(), String> { log::debug!("invoke: reload_all_packages"); let mut appd = state.lock().await; appd.pkgs.reload_all() .await .map_err(|e| e.to_string()) } #[tauri::command] pub async fn get_all_packages(state: State<'_, Mutex>) -> Result, ()> { log::debug!("invoke: get_all_packages"); let appd = state.lock().await; Ok(appd.pkgs.get_all()) } #[tauri::command] pub async fn fetch_listings(state: State<'_, Mutex>) -> Result<(), String> { log::debug!("invoke: fetch_listings"); let mut appd = state.lock().await; appd.pkgs.fetch_listings().await .map_err(|e| e.to_string()) } #[tauri::command] pub async fn list_profiles() -> Result, String> { log::debug!("invoke: list_profiles"); let list = crate::profiles::list_profiles().await.map_err(|e| e.to_string())?; Ok(list) } #[tauri::command] pub async fn init_profile( state: State<'_, Mutex>, game: Game, name: String ) -> Result<(), String> { log::debug!("invoke: init_profile({}, {})", game, name); let mut appd = state.lock().await; let new_profile = OngekiProfile::new(name) .map_err(|e| format!("Unable to create profile: {}", e))?; fs::create_dir_all(new_profile.config_dir()).await .map_err(|e| format!("Unable to create the profile config directory: {}", e))?; fs::create_dir_all(new_profile.data_dir()).await .map_err(|e| format!("Unable to create the profile data directory: {}", e))?; appd.profile = Some(AnyProfile::OngekiProfile(new_profile.clone())); Ok(()) } #[tauri::command] pub async fn load_profile(state: State<'_, Mutex>, game: Game, name: String) -> Result<(), String> { log::debug!("invoke: load_profile({} {:?})", game, name); let mut appd = state.lock().await; appd.switch_profile(game, name).map_err(|e| e.to_string())?; Ok(()) } #[tauri::command] pub async fn rename_profile( state: State<'_, Mutex>, profile: ProfileMeta, name: String ) -> Result<(), String> { log::debug!("invoke: rename_profile({:?} {:?})", profile, name); let new_meta = ProfileMeta { game: profile.game.clone(), name: profiles::fixed_name(&ProfileMeta { game: profile.game.clone(), name }, false) }; if new_meta.name == profile.name { return Ok(()); } if new_meta.config_dir().exists() { return Err(format!("Profile {} already exists", &new_meta.name)); } fs::rename(profile.config_dir(), new_meta.config_dir()).await .map_err(|e| format!("Unable to rename: {}", e))?; if let Err(e) = fs::rename(profile.data_dir(), new_meta.data_dir()).await { log::warn!("Unable to move data dir {}->{}: {}", &profile.name, &new_meta.name, e); } let mut appd = state.lock().await; if let Some(current) = &mut appd.profile { if current.meta() == profile { current.rename(new_meta.name); } } Ok(()) } #[tauri::command] pub async fn duplicate_profile(profile: ProfileMeta) -> Result<(), String> { log::debug!("invoke: duplicate_profile({:?})", profile); let new_meta = ProfileMeta { game: profile.game.clone(), name: profiles::fixed_name(&profile, true) }; util::copy_directory(profile.config_dir(), new_meta.config_dir(), false) .map_err(|e| format!("Unable to duplicate: {}", e))?; Ok(()) } #[tauri::command] pub async fn delete_profile(state: State<'_, Mutex>, profile: ProfileMeta) -> Result<(), String> { log::debug!("invoke: delete_profile({:?})", profile); std::fs::remove_dir_all(profile.config_dir()) .map_err(|e| format!("Unable to delete {:?}: {}", profile.config_dir(), e))?; if let Err(e) = std::fs::remove_dir_all(profile.data_dir()) { log::warn!("Unable to delete: {:?} {}", profile.data_dir(), e); } let mut appd = state.lock().await; if let Some(current) = &mut appd.profile { if current.meta() == profile { appd.profile = None; } } Ok(()) } #[tauri::command] pub async fn get_current_profile(state: State<'_, Mutex>) -> Result, ()> { log::debug!("invoke: get_current_profile"); let appd = state.lock().await; Ok(appd.profile.clone()) } #[tauri::command] pub async fn save_current_profile(state: State<'_, Mutex>, profile: AnyProfile) -> Result<(), String> { log::debug!("invoke: save_current_profile"); let mut appd = state.lock().await; profile.save().map_err(|e| e.to_string())?; appd.profile = Some(profile); Ok(()) } #[tauri::command] pub async fn list_platform_capabilities() -> Result, ()> { log::debug!("invoke: list_platform_capabilities"); #[cfg(target_os = "windows")] return Ok(vec!["display".to_owned()]); #[cfg(target_os = "linux")] return Ok(vec!["wine".to_owned()]); } #[tauri::command] #[cfg(target_os = "windows")] pub async fn list_displays() -> Result, String> { use winsafe::prelude::NativeBitflag; log::debug!("invoke: list_displays"); let mut res = Vec::new(); for displ_dev in winsafe::EnumDisplayDevices(None, None) { if let Ok(displ_dev) = displ_dev { if displ_dev.StateFlags.has(winsafe::co::DISPLAY_DEVICE::ATTACHED_TO_DESKTOP) { res.push((displ_dev.DeviceName(), displ_dev.DeviceString())); } } else { break; } } Ok(res) } #[tauri::command] #[cfg(not(target_os = "windows"))] pub async fn list_displays() -> Result, ()> { log::debug!("invoke: list_displays"); Ok(Vec::new()) } #[tauri::command] pub async fn list_directories() -> Result { log::debug!("invoke: list_directores"); Ok(util::all_dirs().clone()) }