use interpulse::api::minecraft::Version; use onelauncher_entity::{icon::Icon, loader::GameLoader}; use tauri::{AppHandle, Runtime}; use crate::{api::{self, cluster::dao::ClusterId}, error::LauncherResult, store::{credentials::MinecraftCredentials, Core}}; use onelauncher_entity::prelude::model::*; #[taurpc::procedures(path = "core")] pub trait TauriLauncherApi { // Clusters #[taurpc(alias = "getClusters")] async fn get_clusters() -> LauncherResult>; #[taurpc(alias = "getClusterById")] async fn get_cluster_by_id(id: ClusterId) -> LauncherResult>; #[taurpc(alias = "removeCluster")] async fn remove_cluster(id: ClusterId) -> LauncherResult<()>; #[taurpc(alias = "createCluster")] async fn create_cluster(options: CreateCluster) -> LauncherResult; #[taurpc(alias = "launchCluster")] async fn launch_cluster(id: ClusterId, uuid: Option) -> LauncherResult<()>; // #[taurpc(alias = "updateClusterById")] // async fn update_cluster_by_id(id: ClusterId, request: Cluster) -> LauncherResult<()>; // Setting Profiles #[taurpc(alias = "getProfileOrDefault")] async fn get_profile_or_default(name: Option) -> LauncherResult; #[taurpc(alias = "getGlobalProfile")] async fn get_global_profile() -> SettingsProfile; // Game Metadata #[taurpc(alias = "getGameVersions")] async fn get_game_versions() -> LauncherResult>; #[taurpc(alias = "getLoadersForVersion")] async fn get_loaders_for_version(mc_version: String) -> LauncherResult>; // Users #[taurpc(alias = "getUsers")] async fn get_users() -> LauncherResult>; #[taurpc(alias = "getUser")] async fn get_user(uuid: uuid::Uuid) -> LauncherResult>; #[taurpc(alias = "removeUser")] async fn remove_user(uuid: uuid::Uuid) -> LauncherResult<()>; #[taurpc(alias = "getDefaultUser")] async fn get_default_user(fallback: Option) -> LauncherResult>; #[taurpc(alias = "setDefaultUser")] async fn set_default_user(uuid: Option) -> LauncherResult<()>; #[taurpc(alias = "openMsaLogin")] async fn open_msa_login(app_handle: AppHandle) -> LauncherResult>; } #[derive(serde::Serialize, serde::Deserialize, specta::Type, Clone)] pub struct CreateCluster { name: String, mc_version: String, mc_loader: GameLoader, mc_loader_version: Option, icon: Option, } #[taurpc::ipc_type] pub struct TauriLauncherApiImpl; #[taurpc::resolvers] impl TauriLauncherApi for TauriLauncherApiImpl { // Clusters async fn get_clusters(self) -> LauncherResult> { api::cluster::dao::get_all_clusters().await } async fn get_cluster_by_id(self, id: ClusterId) -> LauncherResult> { api::cluster::dao::get_cluster_by_id(id).await } async fn remove_cluster(self, id: ClusterId) -> LauncherResult<()> { api::cluster::dao::delete_cluster_by_id(id).await } async fn create_cluster(self, options: CreateCluster) -> LauncherResult { let cluster = api::cluster::create_cluster(&options.name, &options.mc_version, options.mc_loader, options.mc_loader_version.as_deref(), options.icon).await?; Ok(cluster) } async fn launch_cluster(self, id: ClusterId, uuid: Option) -> LauncherResult<()> { let mut cluster = api::cluster::dao::get_cluster_by_id(id).await? .ok_or_else(|| anyhow::anyhow!("cluster with id {} not found", id))?; let uuid = match uuid { Some(uuid) => uuid, None => api::credentials::get_default_user().await?.ok_or_else(|| anyhow::anyhow!("no default user set"))?, }; let user = api::credentials::get_user(uuid).await? .ok_or_else(|| anyhow::anyhow!("user with uuid {} not found", uuid))?; // let user = api::credentials::get_fake_user(); let _ = api::game::launch::launch_minecraft(&mut cluster, user, None).await?; Ok(()) } // async fn update_cluster_by_id(self, id: ClusterId, request: clusters::ActiveModel) -> LauncherResult<()> { // // let updated_cluster = api::cluster::dao::update_cluster_by_id(id, |mut active_model| async move { // // if let Some(name) = request.name { // // active_model.name = Set(name); // // } // // active_model.updated_at = Set(chrono::Utc::now().naive_utc()); // // Ok(active_model) // // }) // // .await // // .map_err(|e| e.to_string())?; // Ok(()) // } // Setting Profiles async fn get_global_profile(self) -> SettingsProfile { api::setting_profiles::get_global_profile().await } async fn get_profile_or_default(self, name: Option) -> LauncherResult { api::setting_profiles::dao::get_profile_or_default(name.as_ref()).await } // Game Metadata async fn get_loaders_for_version(self, mc_version: String) -> LauncherResult> { api::game::metadata::get_loaders_for_version(&mc_version).await } async fn get_game_versions(self) -> LauncherResult> { api::game::metadata::get_game_versions().await } // Users async fn get_users(self) -> LauncherResult> { api::credentials::get_users().await } async fn get_user(self, uuid: uuid::Uuid) -> LauncherResult> { api::credentials::get_user(uuid).await } async fn remove_user(self, uuid: uuid::Uuid) -> LauncherResult<()> { api::credentials::remove_user(uuid).await } async fn get_default_user(self, fallback: Option) -> LauncherResult> { let uuid = api::credentials::get_default_user().await?; if fallback.is_some_and(|fallback| fallback) && uuid.is_none() { return Ok(api::credentials::get_users().await?.first().cloned()); } match uuid { Some(uuid) => Ok(api::credentials::get_user(uuid).await?), None => Ok(None), } } async fn set_default_user(self, uuid: Option) -> LauncherResult<()> { api::credentials::set_default_user(uuid).await } async fn open_msa_login(self, app_handle: AppHandle) -> LauncherResult> { use tauri::Manager; let flow = api::credentials::begin().await?; let now = chrono::Utc::now(); if let Some(win) = app_handle.get_webview_window("login") { win.close()?; } let win = tauri::WebviewWindowBuilder::new( &app_handle, "login", tauri::WebviewUrl::External( flow.redirect_uri .parse() .map_err(|_| anyhow::anyhow!("failed to parse auth redirect url"))?, ), ) .title(format!("Login to {}", Core::get().launcher_name)) .center() .focused(true) .build()?; win.request_user_attention(Some(tauri::UserAttentionType::Critical))?; while (chrono::Utc::now() - now) < chrono::Duration::minutes(10) { if win.title().is_err() { return Ok(None); } if win .url()? .as_str() .starts_with("https://login.live.com/oauth20_desktop.srf") { if let Some((_, code)) = win .url()? .query_pairs() .find(|x| x.0 == "code") { win.close()?; let value = api::credentials::finish(&code.clone(), flow).await?; return Ok(Some(value)); } } tokio::time::sleep(std::time::Duration::from_millis(50)).await; } win.close()?; Ok(None) } }