chore: migrate to taurpc
This commit is contained in:
parent
aad3e058d0
commit
521b3cfdc9
54 changed files with 712 additions and 1323 deletions
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
|
|
@ -24,10 +24,11 @@
|
|||
"**/routeTree.gen.ts": true
|
||||
},
|
||||
"rust-analyzer.procMacro.enable": true,
|
||||
"rust-analyzer.procMacro.attributes.enable": false,
|
||||
"rust-analyzer.procMacro.attributes.enable": true,
|
||||
"rust-analyzer.diagnostics.disabled": [
|
||||
"macro-error" // TODO: Remove this once taurpc upgrades to latest specta
|
||||
],
|
||||
"rust-analyzer.procMacro.ignored": {
|
||||
"async-trait": ["async_trait"],
|
||||
"specta": ["specta"],
|
||||
"tauri-specta": ["command"]
|
||||
},
|
||||
"rust-analyzer.check.command": "check",
|
||||
|
|
|
|||
110
Cargo.lock
generated
110
Cargo.lock
generated
|
|
@ -2518,6 +2518,15 @@ version = "1.70.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
|
|
@ -3365,7 +3374,6 @@ dependencies = [
|
|||
"tauri-plugin-single-instance",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
"tauri-specta",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
|
@ -3415,7 +3423,7 @@ dependencies = [
|
|||
"specta",
|
||||
"sysinfo",
|
||||
"tauri",
|
||||
"tauri-specta",
|
||||
"taurpc",
|
||||
"tempfile",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
|
|
@ -3475,7 +3483,7 @@ dependencies = [
|
|||
"tauri-plugin-single-instance",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
"tauri-specta",
|
||||
"taurpc",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
|
@ -5231,13 +5239,14 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "specta"
|
||||
version = "2.0.0-rc.22"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=30661263250e7b6f9b36cdc56e6c843ac5abb226#30661263250e7b6f9b36cdc56e6c843ac5abb226"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=5758221bc9a11d6e827851273fd665662e90ceef#5758221bc9a11d6e827851273fd665662e90ceef"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"ctor",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"specta-macros",
|
||||
"specta-macros 2.0.0-rc.18 (git+https://github.com/specta-rs/specta?rev=5758221bc9a11d6e827851273fd665662e90ceef)",
|
||||
"thiserror 1.0.64",
|
||||
"tokio",
|
||||
"uuid 1.16.0",
|
||||
|
|
@ -5246,7 +5255,19 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "specta-macros"
|
||||
version = "2.0.0-rc.18"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=30661263250e7b6f9b36cdc56e6c843ac5abb226#30661263250e7b6f9b36cdc56e6c843ac5abb226"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0074b9e30ed84c6924eb63ad8d2fe71cdc82628525d84b1fcb1f2fd40676517"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "specta-macros"
|
||||
version = "2.0.0-rc.18"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=5758221bc9a11d6e827851273fd665662e90ceef#5758221bc9a11d6e827851273fd665662e90ceef"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
|
|
@ -5257,7 +5278,17 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "specta-serde"
|
||||
version = "0.0.9"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=30661263250e7b6f9b36cdc56e6c843ac5abb226#30661263250e7b6f9b36cdc56e6c843ac5abb226"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77216504061374659e7245eac53d30c7b3e5fe64b88da97c753e7184b0781e63"
|
||||
dependencies = [
|
||||
"specta",
|
||||
"thiserror 1.0.64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "specta-serde"
|
||||
version = "0.0.9"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=5758221bc9a11d6e827851273fd665662e90ceef#5758221bc9a11d6e827851273fd665662e90ceef"
|
||||
dependencies = [
|
||||
"specta",
|
||||
"thiserror 1.0.64",
|
||||
|
|
@ -5266,10 +5297,10 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "specta-typescript"
|
||||
version = "0.0.9"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=30661263250e7b6f9b36cdc56e6c843ac5abb226#30661263250e7b6f9b36cdc56e6c843ac5abb226"
|
||||
source = "git+https://github.com/specta-rs/specta?rev=5758221bc9a11d6e827851273fd665662e90ceef#5758221bc9a11d6e827851273fd665662e90ceef"
|
||||
dependencies = [
|
||||
"specta",
|
||||
"specta-serde",
|
||||
"specta-serde 0.0.9 (git+https://github.com/specta-rs/specta?rev=5758221bc9a11d6e827851273fd665662e90ceef)",
|
||||
"thiserror 1.0.64",
|
||||
]
|
||||
|
||||
|
|
@ -6089,34 +6120,6 @@ dependencies = [
|
|||
"wry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-specta"
|
||||
version = "2.0.0-rc.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b23c0132dd3cf6064e5cd919b82b3f47780e9280e7b5910babfe139829b76655"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"specta",
|
||||
"specta-typescript",
|
||||
"tauri",
|
||||
"tauri-specta-macros",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-specta-macros"
|
||||
version = "2.0.0-rc.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a4aa93823e07859546aa796b8a5d608190cd8037a3a5dce3eb63d491c34bda8"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.4.0"
|
||||
|
|
@ -6166,6 +6169,39 @@ dependencies = [
|
|||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "taurpc"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c34f21c40a46c1e5f859eeb51427706dde816b55d6d9baf2dab4d952aff191a1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"heck 0.5.0",
|
||||
"itertools",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"specta",
|
||||
"specta-macros 2.0.0-rc.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"specta-serde 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"specta-typescript",
|
||||
"tauri",
|
||||
"taurpc-macros",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "taurpc-macros"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39137974c051ae93c437b004082541bd0f2f0f69c0d9e30c16266983cd952d4f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.19.1"
|
||||
|
|
|
|||
16
Cargo.toml
16
Cargo.toml
|
|
@ -61,13 +61,10 @@ specta = { version = "=2.0.0-rc.22", features = [
|
|||
"serde_json",
|
||||
"function",
|
||||
"derive",
|
||||
"tokio"
|
||||
"tokio",
|
||||
] }
|
||||
specta-typescript = { version = "=0.0.9" }
|
||||
tauri-specta = { version = "=2.0.0-rc.21", features = [
|
||||
"derive",
|
||||
"typescript"
|
||||
] }
|
||||
taurpc = { version = "=0.5.0" }
|
||||
|
||||
# logging
|
||||
tracing = { version = "0.1" }
|
||||
|
|
@ -182,8 +179,11 @@ proc-macro2 = { version = "1" }
|
|||
|
||||
[patch.crates-io]
|
||||
# tauri-specta = { git = "https://github.com/specta-rs/tauri-specta", rev = "6fe9532a44b8b683b4dacd178b0120ee585bea23" }
|
||||
specta = { git = "https://github.com/specta-rs/specta", rev = "30661263250e7b6f9b36cdc56e6c843ac5abb226" }
|
||||
specta-typescript = { git = "https://github.com/specta-rs/specta", rev = "30661263250e7b6f9b36cdc56e6c843ac5abb226" }
|
||||
specta = { git = "https://github.com/specta-rs/specta", rev = "5758221bc9a11d6e827851273fd665662e90ceef" }
|
||||
specta-typescript = { git = "https://github.com/specta-rs/specta", rev = "5758221bc9a11d6e827851273fd665662e90ceef" }
|
||||
|
||||
[workspace.lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(feature, values("used_linker"))' ] }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
all = { level = "warn", priority = -1 }
|
||||
|
|
@ -253,4 +253,4 @@ codegen-units = 1 # compile crate one after another for better optimization
|
|||
lto = true # enable link time optimization
|
||||
opt-level = "s" # optimize binary
|
||||
panic = "abort" # strip panic cleanup logic
|
||||
strip = true # remove debug symbols
|
||||
strip = true
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ tauri-plugin-dialog = { workspace = true }
|
|||
tauri-plugin-deep-link = { workspace = true }
|
||||
|
||||
# code gen
|
||||
tauri-specta = { workspace = true }
|
||||
specta = { workspace = true }
|
||||
specta-typescript = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
pub mod cluster;
|
||||
pub mod users;
|
||||
pub mod processor;
|
||||
pub mod package;
|
||||
pub mod other;
|
||||
pub mod settings;
|
||||
// pub mod cluster;
|
||||
// pub mod users;
|
||||
// pub mod processor;
|
||||
// pub mod package;
|
||||
// pub mod other;
|
||||
// pub mod settings;
|
||||
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! collect_commands {
|
||||
() => {{
|
||||
use $crate::api::commands::*;
|
||||
tauri_specta::collect_commands![
|
||||
users::get_users,
|
||||
users::get_user,
|
||||
users::remove_user,
|
||||
users::get_default_user,
|
||||
users::set_default_user,
|
||||
users::begin_ms_flow,
|
||||
// #[macro_export(local_inner_macros)]
|
||||
// macro_rules! collect_commands {
|
||||
// () => {{
|
||||
// use $crate::api::commands::*;
|
||||
// tauri_specta::collect_commands![
|
||||
// users::get_users,
|
||||
// users::get_user,
|
||||
// users::remove_user,
|
||||
// users::get_default_user,
|
||||
// users::set_default_user,
|
||||
// users::begin_ms_flow,
|
||||
|
||||
cluster::create_cluster,
|
||||
cluster::get_clusters,
|
||||
cluster::get_cluster_by_id,
|
||||
// cluster::create_cluster,
|
||||
// cluster::get_clusters,
|
||||
// cluster::get_cluster_by_id,
|
||||
|
||||
settings::get_global_profile,
|
||||
settings::get_profile_or_default,
|
||||
// settings::get_global_profile,
|
||||
// settings::get_profile_or_default,
|
||||
|
||||
other::open_dev_tools,
|
||||
]
|
||||
}};
|
||||
}
|
||||
// other::open_dev_tools,
|
||||
// ]
|
||||
// }};
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#[macro_export]
|
||||
macro_rules! collect_events {
|
||||
() => {{
|
||||
tauri_specta::collect_events! {
|
||||
onelauncher_core::api::proxy::event::LauncherEvent
|
||||
}
|
||||
}};
|
||||
}
|
||||
// #[macro_export]
|
||||
// macro_rules! collect_events {
|
||||
// () => {{
|
||||
// tauri_specta::collect_events! {
|
||||
// onelauncher_core::api::proxy::event::LauncherEvent
|
||||
// }
|
||||
// }};
|
||||
// }
|
||||
|
|
@ -7,7 +7,7 @@ use tauri::{Emitter, Manager};
|
|||
|
||||
pub mod api;
|
||||
pub mod constants;
|
||||
pub mod ext;
|
||||
// pub mod ext;
|
||||
|
||||
#[derive(Clone, serde::Serialize)]
|
||||
pub struct SingleInstancePayload {
|
||||
|
|
@ -38,19 +38,19 @@ async fn initialize_core() -> LauncherResult<()> {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn initialize_tauri(builder: tauri::Builder<tauri::Wry>) -> LauncherResult<tauri::App> {
|
||||
let prebuild = tauri_specta::Builder::<tauri::Wry>::new()
|
||||
.commands(collect_commands!())
|
||||
.events(collect_events!());
|
||||
// let prebuild = tauri_specta::Builder::<tauri::Wry>::new()
|
||||
// .commands(collect_commands!())
|
||||
// .events(collect_events!());
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
prebuild
|
||||
.export(
|
||||
specta_typescript::Typescript::default()
|
||||
.bigint(specta_typescript::BigIntExportBehavior::BigInt)
|
||||
.formatter(ext::specta::formatter),
|
||||
"../frontend/src/bindings.gen.ts",
|
||||
)
|
||||
.expect("failed to export debug bindings!");
|
||||
// #[cfg(debug_assertions)]
|
||||
// prebuild
|
||||
// .export(
|
||||
// specta_typescript::Typescript::default()
|
||||
// .bigint(specta_typescript::BigIntExportBehavior::BigInt)
|
||||
// .formatter(ext::specta::formatter),
|
||||
// "../frontend/src/bindings.gen.ts",
|
||||
// )
|
||||
// .expect("failed to export debug bindings!");
|
||||
|
||||
let builder = builder
|
||||
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
|
||||
|
|
@ -60,15 +60,15 @@ async fn initialize_tauri(builder: tauri::Builder<tauri::Wry>) -> LauncherResult
|
|||
}))
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(ext::updater::plugin())
|
||||
.manage(ext::updater::State::default())
|
||||
// .plugin(ext::updater::plugin())
|
||||
// .manage(ext::updater::State::default())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
// .plugin(api::init())
|
||||
.menu(tauri::menu::Menu::new)
|
||||
.invoke_handler(prebuild.invoke_handler())
|
||||
// .invoke_handler(prebuild.invoke_handler())
|
||||
.setup(move |app| {
|
||||
prebuild.mount_events(app.handle());
|
||||
// prebuild.mount_events(app.handle());
|
||||
setup_window(app.handle()).expect("failed to setup main window");
|
||||
Ok(())
|
||||
});
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ tauri-plugin-dialog = { workspace = true }
|
|||
tauri-plugin-deep-link = { workspace = true }
|
||||
|
||||
# code gen
|
||||
tauri-specta = { workspace = true }
|
||||
taurpc = { workspace = true }
|
||||
specta = { workspace = true }
|
||||
specta-typescript = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -1,30 +1,27 @@
|
|||
pub mod cluster;
|
||||
pub mod users;
|
||||
pub mod processor;
|
||||
pub mod package;
|
||||
pub mod other;
|
||||
pub mod settings;
|
||||
use onelauncher_core::error::{DaoError, LauncherResult};
|
||||
use tauri::Runtime;
|
||||
|
||||
#[macro_export(local_inner_macros)]
|
||||
macro_rules! collect_commands {
|
||||
() => {{
|
||||
use $crate::api::commands::*;
|
||||
tauri_specta::collect_commands![
|
||||
users::get_users,
|
||||
users::get_user,
|
||||
users::remove_user,
|
||||
users::get_default_user,
|
||||
users::set_default_user,
|
||||
users::begin_ms_flow,
|
||||
#[taurpc::procedures(path = "onelauncher", export_to = "../frontend/src/bindings.gen.ts")]
|
||||
pub trait OneLauncherApi {
|
||||
async fn return_error() -> LauncherResult<()>;
|
||||
|
||||
async fn open_dev_tools<R: Runtime>(webview_window: tauri::WebviewWindow<R>);
|
||||
}
|
||||
|
||||
#[taurpc::ipc_type]
|
||||
pub struct OneLauncherApiImpl;
|
||||
|
||||
#[taurpc::resolvers]
|
||||
impl OneLauncherApi for OneLauncherApiImpl {
|
||||
|
||||
async fn return_error(self) -> LauncherResult<()> {
|
||||
let err = DaoError::NotFound.into();
|
||||
Err(err)
|
||||
}
|
||||
|
||||
async fn open_dev_tools<R: Runtime>(self, webview_window: tauri::WebviewWindow<R>) {
|
||||
#[cfg(feature = "devtools")]
|
||||
webview_window.open_devtools();
|
||||
}
|
||||
|
||||
cluster::create_cluster,
|
||||
cluster::get_clusters,
|
||||
cluster::get_cluster_by_id,
|
||||
|
||||
settings::get_global_profile,
|
||||
settings::get_profile_or_default,
|
||||
|
||||
other::open_dev_tools,
|
||||
]
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,262 +0,0 @@
|
|||
// use std::collections::HashMap;
|
||||
// use std::path::PathBuf;
|
||||
// use std::str::FromStr;
|
||||
|
||||
// use onelauncher_core::cluster::content::logger;
|
||||
// use onelauncher_core::cluster::{self};
|
||||
// use onelauncher_core::data::{Loader, PackageData};
|
||||
// use onelauncher_core::processor::DetailedProcess;
|
||||
// use onelauncher_core::store::{Cluster, ClusterPath};
|
||||
// use onelauncher_core::api::java::JavaInfo;
|
||||
// use onelauncher_core::store::State;
|
||||
// use serde::{Deserialize, Serialize};
|
||||
// use specta::Type;
|
||||
// use uuid::Uuid;
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_cluster(uuid: Uuid) -> Result<Cluster, String> {
|
||||
// (cluster::get_by_uuid(uuid).await?).map_or_else(|| Err("Cluster does not exist".into()), Ok)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_clusters() -> Result<Vec<Cluster>, String> {
|
||||
// Ok(cluster::list().await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_clusters_grouped() -> Result<HashMap<String, Vec<Cluster>>, String> {
|
||||
// Ok(cluster::list_grouped().await?)
|
||||
// }
|
||||
|
||||
// #[derive(Serialize, Deserialize, Type)]
|
||||
// pub struct CreateCluster {
|
||||
// name: String,
|
||||
// mc_version: String,
|
||||
// mod_loader: Loader,
|
||||
// loader_version: Option<String>,
|
||||
// icon: Option<PathBuf>,
|
||||
// icon_url: Option<String>,
|
||||
// package_data: Option<PackageData>,
|
||||
// skip: Option<bool>,
|
||||
// skip_watch: Option<bool>,
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn create_cluster(props: CreateCluster) -> Result<Uuid, String> {
|
||||
// let path = cluster::create::create_cluster(
|
||||
// props.name,
|
||||
// props.mc_version,
|
||||
// props.mod_loader,
|
||||
// props.loader_version,
|
||||
// props.icon,
|
||||
// props.icon_url,
|
||||
// props.package_data,
|
||||
// props.skip,
|
||||
// props.skip_watch,
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// if let Some(cluster) = cluster::get(&path).await? {
|
||||
// Ok(cluster.uuid)
|
||||
// } else {
|
||||
// Err("Cluster does not exist".to_string())
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// Updates the cluster with the given UUID. The cluster only updates game setting fields
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn edit_game_settings(uuid: Uuid, new_cluster: Cluster) -> Result<(), String> {
|
||||
// let cluster_path = ClusterPath::find_by_uuid(uuid).await?;
|
||||
|
||||
// cluster::edit(&cluster_path, |old| {
|
||||
// old.force_fullscreen = new_cluster.force_fullscreen;
|
||||
// old.resolution = new_cluster.resolution;
|
||||
// old.memory = new_cluster.memory;
|
||||
// old.init_hooks.clone_from(&new_cluster.init_hooks);
|
||||
// old.java.clone_from(&new_cluster.java);
|
||||
|
||||
// async move { Ok(()) }
|
||||
// })
|
||||
// .await?;
|
||||
|
||||
// State::sync().await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn edit_cluster_meta(
|
||||
// uuid: Uuid,
|
||||
// name: Option<String>,
|
||||
// icon_path: Option<String>,
|
||||
// ) -> Result<(), String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster does not exist")?;
|
||||
|
||||
// cluster::edit(&cluster.cluster_path(), move |cluster| {
|
||||
// if let Some(name) = name.clone() {
|
||||
// cluster.meta.name = name;
|
||||
// }
|
||||
|
||||
// async move { Ok(()) }
|
||||
// })
|
||||
// .await?;
|
||||
|
||||
// let icon_path = icon_path.and_then(|x| PathBuf::from_str(x.as_str()).ok());
|
||||
// cluster::edit_icon(&cluster.cluster_path(), icon_path.as_deref()).await?;
|
||||
|
||||
// State::sync().await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn remove_cluster(uuid: Uuid) -> Result<(), String> {
|
||||
// let path = ClusterPath::find_by_uuid(uuid).await?;
|
||||
// Ok(cluster::remove(&path).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn run_cluster(uuid: Uuid) -> Result<DetailedProcess, String> {
|
||||
// let path = ClusterPath::find_by_uuid(uuid).await?;
|
||||
// let c_lock = cluster::run_default(&path).await?;
|
||||
// let child = &*c_lock.read().await;
|
||||
|
||||
// Ok(DetailedProcess::from_processor_child(child).await)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_cluster_logs(uuid: Uuid) -> Result<Vec<String>, String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
// let logs = logger::get_logs(&cluster.cluster_path(), None)
|
||||
// .await?
|
||||
// .iter()
|
||||
// .map(|x| x.log_file.clone())
|
||||
// .collect();
|
||||
// Ok(logs)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_cluster_log(uuid: Uuid, log_name: String) -> Result<String, String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
// let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name)
|
||||
// .await?;
|
||||
// Ok(log.0)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn upload_log(uuid: Uuid, log_name: String) -> Result<String, String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
// let log = logger::get_output_by_file(&cluster.cluster_path(), logger::LogType::Info, &log_name)
|
||||
// .await?;
|
||||
|
||||
// let id = logger::upload_log(&cluster.cluster_path(), log).await?;
|
||||
// Ok(id)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_screenshots(uuid: Uuid) -> Result<Vec<String>, String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
|
||||
// let screenshots =
|
||||
// cluster::content::screenshots::get_screenshots(&cluster.cluster_path()).await?;
|
||||
|
||||
// Ok(screenshots)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_worlds(uuid: Uuid) -> Result<Vec<String>, String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
|
||||
// let screenshots = cluster::content::worlds::get_worlds(&cluster.cluster_path()).await?;
|
||||
|
||||
// Ok(screenshots)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_optimal_java_version(uuid: Uuid) -> Result<JavaVersion, String> {
|
||||
// let cluster_path = cluster::get_by_uuid(uuid).await?.ok_or("Cluster not found")?.cluster_path();
|
||||
// Ok(cluster::get_optimal_java_version(&cluster_path).await?.ok_or("No Java version found")?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn repair_cluster(uuid: Uuid) -> Result<(), String> {
|
||||
// let cluster = cluster::get_by_uuid(uuid)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
|
||||
// cluster::repair_cluster(&cluster.cluster_path()).await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
use onelauncher_core::{api::{cluster, setting_profiles}, entity::{clusters::Model, icon::Icon, loader::GameLoader}, error::LauncherResult, migration::sea_orm};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use specta::Type;
|
||||
use crate::api::error::SerializableResult;
|
||||
|
||||
#[derive(Serialize, Deserialize, Type)]
|
||||
pub struct CreateCluster {
|
||||
name: String,
|
||||
mc_version: String,
|
||||
mc_loader: GameLoader,
|
||||
mc_loader_version: Option<String>,
|
||||
icon_url: Option<Icon>
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn create_cluster(options: CreateCluster) -> SerializableResult<Model> {
|
||||
let thing = cluster::create_cluster(&options.name, &options.mc_version, options.mc_loader, options.mc_loader_version.as_deref(), options.icon_url).await?;
|
||||
|
||||
// cluster::prepare_cluster(&mut thing.clone(), Some(false));
|
||||
|
||||
if setting_profiles::dao::get_profile_by_name(&options.name).await?.is_none() {
|
||||
setting_profiles::create_profile(&options.name, async |mut profile| {
|
||||
profile.mem_max = sea_orm::ActiveValue::Set(Some(2048));
|
||||
Ok(profile)
|
||||
}).await?;
|
||||
}
|
||||
|
||||
Ok(thing)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_clusters() -> SerializableResult<Vec<Model>> {
|
||||
Ok(cluster::dao::get_all_clusters().await?)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_cluster_by_id(id: i64) -> SerializableResult<Option<Model>> {
|
||||
Ok(cluster::dao::get_cluster_by_id(id).await?)
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
#[onelauncher_core::command]
|
||||
#[allow(unused_parens)]
|
||||
pub fn open_dev_tools(webview: tauri::WebviewWindow) {
|
||||
#[cfg(feature = "devtools")]
|
||||
webview.open_devtools();
|
||||
}
|
||||
|
|
@ -1,234 +0,0 @@
|
|||
// use std::path::PathBuf;
|
||||
|
||||
// use onelauncher::cluster::content::package;
|
||||
// use onelauncher::data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType};
|
||||
// use onelauncher::package::content::Providers;
|
||||
// use onelauncher::package::import::ImportType;
|
||||
// use onelauncher::store::{
|
||||
// Author, ClusterPath, Package, PackageBody, PackagePath, ProviderSearchResults,
|
||||
// };
|
||||
// use onelauncher::utils::pagination::Pagination;
|
||||
// use uuid::Uuid;
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_launcher_instances(
|
||||
// launcher: ImportType,
|
||||
// path: Option<PathBuf>,
|
||||
// ) -> Result<(String, Vec<String>), String> {
|
||||
// let (dir, instances) = onelauncher::api::package::import::get_launcher_instances(launcher, path).await?;
|
||||
// Ok((
|
||||
// dir.to_str().ok_or("could not convert pathbuf to string")?.to_string(),
|
||||
// instances
|
||||
// ))
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn import_instances(
|
||||
// launcher: ImportType,
|
||||
// base_path: PathBuf,
|
||||
// instances: Vec<String>,
|
||||
// ) -> Result<(), String> {
|
||||
// onelauncher::api::package::import::import_instances(launcher, base_path, instances).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_provider_package(
|
||||
// provider: Providers,
|
||||
// project_id: String,
|
||||
// ) -> Result<ManagedPackage, String> {
|
||||
// Ok(provider.get(&project_id).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_provider_packages(
|
||||
// provider: Providers,
|
||||
// project_ids: Vec<String>,
|
||||
// ) -> Result<Vec<ManagedPackage>, String> {
|
||||
// Ok(provider.get_multiple(&project_ids).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_all_provider_package_versions(
|
||||
// provider: Providers,
|
||||
// project_id: String,
|
||||
// game_versions: Option<Vec<String>>,
|
||||
// loaders: Option<Vec<Loader>>,
|
||||
// page: Option<u32>,
|
||||
// page_size: Option<u16>,
|
||||
// ) -> Result<(Vec<ManagedVersion>, Pagination), String> {
|
||||
// Ok(provider
|
||||
// .get_all_versions(&project_id, game_versions, loaders, page, page_size)
|
||||
// .await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_provider_package_versions(
|
||||
// provider: Providers,
|
||||
// versions: Vec<String>,
|
||||
// ) -> Result<Vec<ManagedVersion>, String> {
|
||||
// Ok(provider.get_versions(versions).await?)
|
||||
// }
|
||||
|
||||
// #[derive(specta::Type, serde::Deserialize, serde::Serialize)]
|
||||
// pub struct ProviderSearchQuery {
|
||||
// query: Option<String>,
|
||||
// limit: Option<u8>,
|
||||
// offset: Option<u32>,
|
||||
// game_versions: Option<Vec<String>>,
|
||||
// categories: Option<Vec<String>>,
|
||||
// loaders: Option<Vec<Loader>>,
|
||||
// package_types: Option<Vec<PackageType>>,
|
||||
// open_source: Option<bool>,
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn search_provider_packages(
|
||||
// provider: Providers,
|
||||
// query: ProviderSearchQuery,
|
||||
// ) -> Result<ProviderSearchResults, String> {
|
||||
// Ok(provider
|
||||
// .search(
|
||||
// query.query,
|
||||
// query.limit,
|
||||
// query.offset,
|
||||
// query.game_versions,
|
||||
// query.categories,
|
||||
// query.loaders,
|
||||
// query.package_types,
|
||||
// query.open_source,
|
||||
// )
|
||||
// .await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_provider_authors(
|
||||
// provider: Providers,
|
||||
// author: Author,
|
||||
// ) -> Result<Vec<ManagedUser>, String> {
|
||||
// Ok(provider.get_authors(&author).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_package_body(provider: Providers, body: PackageBody) -> Result<String, String> {
|
||||
// Ok(provider.get_package_body(&body).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn download_provider_package(
|
||||
// provider: Providers,
|
||||
// package_id: String,
|
||||
// cluster_id: Uuid,
|
||||
// game_version: Option<String>,
|
||||
// loader: Option<Loader>,
|
||||
// package_version: Option<String>,
|
||||
// ) -> Result<(), String> {
|
||||
// let mut cluster = onelauncher::cluster::get_by_uuid(cluster_id)
|
||||
// .await?
|
||||
// .ok_or("cluster not found")?;
|
||||
|
||||
// let mgd_pkg = provider.get(&package_id).await?;
|
||||
|
||||
// let (pkg_path, pkg) = package::download_package(
|
||||
// &mgd_pkg,
|
||||
// &mut cluster,
|
||||
// game_version,
|
||||
// loader,
|
||||
// package_version,
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// package::add_package(
|
||||
// &cluster.cluster_path(),
|
||||
// pkg_path,
|
||||
// pkg,
|
||||
// )
|
||||
// .await?;
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_cluster_package(
|
||||
// cluster_path: ClusterPath,
|
||||
// package_path: PackagePath,
|
||||
// package_type: PackageType,
|
||||
// ) -> Result<Package, String> {
|
||||
// Ok(package::get_package(&cluster_path, &package_path, package_type).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_cluster_packages(
|
||||
// cluster_path: ClusterPath,
|
||||
// package_type: PackageType,
|
||||
// ) -> Result<Vec<Package>, String> {
|
||||
// Ok(package::get_packages(&cluster_path, package_type).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn add_cluster_package(
|
||||
// cluster_path: ClusterPath,
|
||||
// file_name: String,
|
||||
// package_type: PackageType,
|
||||
// pkg: Package,
|
||||
// ) -> Result<(), String> {
|
||||
// let package_path = PackagePath::new(package_type, file_name)?;
|
||||
// package::add_package(&cluster_path, package_path, pkg).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn remove_cluster_package(
|
||||
// cluster_path: ClusterPath,
|
||||
// file_name: String,
|
||||
// package_type: PackageType,
|
||||
// ) -> Result<(), String> {
|
||||
// let package_path = PackagePath::new(package_type, file_name)?;
|
||||
// package::remove_package(&cluster_path, &package_path).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn set_cluster_package_enabled(
|
||||
// cluster_path: ClusterPath,
|
||||
// file_name: String,
|
||||
// package_type: PackageType,
|
||||
// enabled: bool,
|
||||
// ) -> Result<(), String> {
|
||||
// let package_path = PackagePath::new(package_type, file_name)?;
|
||||
// package::set_package_enabled(&cluster_path, &package_path, enabled).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn sync_cluster_packages(cluster_path: ClusterPath) -> Result<(), String> {
|
||||
// package::sync_packages(&cluster_path).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn sync_cluster_packages_by_type(
|
||||
// cluster_path: ClusterPath,
|
||||
// package_type: PackageType,
|
||||
// clear: Option<bool>,
|
||||
// ) -> Result<(), String> {
|
||||
// package::sync_packages_by_type(&cluster_path, package_type, clear).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
// use chrono::{DateTime, Utc};
|
||||
// use onelauncher::processor::{self, DetailedProcess};
|
||||
// use onelauncher::store::{Cluster, ClusterPath};
|
||||
// use uuid::Uuid;
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_running_clusters() -> Result<Vec<Cluster>, String> {
|
||||
// Ok(processor::get_running_clusters().await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn is_cluster_running(uuid: Uuid) -> Result<bool, String> {
|
||||
// Ok(processor::is_cluster_running(uuid).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_processes_by_path(path: ClusterPath) -> Result<Vec<Uuid>, String> {
|
||||
// Ok(processor::get_uuids_by_cluster_path(path).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_processes_detailed_by_path(
|
||||
// path: ClusterPath,
|
||||
// ) -> Result<Vec<DetailedProcess>, String> {
|
||||
// Ok(processor::get_processes_detailed_by_path(path).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_process_detailed_by_id(uuid: Uuid) -> Result<DetailedProcess, String> {
|
||||
// Ok(processor::get_process_detailed_by_id(uuid).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_user_by_process(uuid: Uuid) -> Result<Option<Uuid>, String> {
|
||||
// Ok(processor::get_user_by_process(uuid).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_process_started_at(uuid: Uuid) -> Result<DateTime<Utc>, String> {
|
||||
// Ok(processor::get_process_started_at(uuid).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn get_pid_by_uuid(uuid: Uuid) -> Result<u32, String> {
|
||||
// Ok(processor::get_pid_by_uuid(uuid).await?)
|
||||
// }
|
||||
|
||||
// #[specta::specta]
|
||||
// #[tauri::command]
|
||||
// pub async fn kill_process(uuid: Uuid) -> Result<(), String> {
|
||||
// processor::kill_by_uuid(uuid).await?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
use onelauncher_core::entity::setting_profiles::Model as SettingsModel;
|
||||
use onelauncher_core::api::setting_profiles;
|
||||
|
||||
use crate::api::error::SerializableResult;
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_global_profile() -> SerializableResult<SettingsModel> {
|
||||
Ok(setting_profiles::get_global_profile().await)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_profile_or_default(
|
||||
name: Option<String>,
|
||||
) -> SerializableResult<SettingsModel> {
|
||||
Ok(setting_profiles::dao::get_profile_or_default(name.as_ref()).await?)
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
use onelauncher_core::{api::credentials, error::LauncherResult, store::{credentials::{MinecraftCredentials, MinecraftLogin}, Core}};
|
||||
use tauri::{AppHandle, Manager};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::api::error::SerializableResult;
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_users() -> SerializableResult<Vec<MinecraftCredentials>> {
|
||||
Ok(credentials::users().await?)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_user(uuid: Uuid) -> SerializableResult<MinecraftCredentials> {
|
||||
Ok(credentials::get_user(uuid).await?)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn remove_user(uuid: Uuid) -> SerializableResult<()> {
|
||||
Ok(credentials::remove_user(uuid).await?)
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn get_default_user(
|
||||
fallback: Option<bool>,
|
||||
) -> SerializableResult<Option<MinecraftCredentials>> {
|
||||
let uuid = credentials::get_default_user().await?;
|
||||
|
||||
if fallback.is_some_and(|fallback| fallback) && uuid.is_none() {
|
||||
return Ok(credentials::users().await?.first().cloned());
|
||||
}
|
||||
|
||||
match uuid {
|
||||
Some(uuid) => Ok(Some(credentials::get_user(uuid).await?)),
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn set_default_user(uuid: Option<Uuid>) -> SerializableResult<()> {
|
||||
credentials::set_default_user(uuid).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[specta::specta]
|
||||
#[tauri::command]
|
||||
pub async fn begin_ms_flow(handle: tauri::AppHandle) -> SerializableResult<Option<MinecraftCredentials>> {
|
||||
let flow = credentials::begin().await?;
|
||||
let result = spawn_webview(handle, flow).await?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn spawn_webview(
|
||||
handle: AppHandle,
|
||||
flow: MinecraftLogin,
|
||||
) -> LauncherResult<Option<MinecraftCredentials>> {
|
||||
let now = chrono::Utc::now();
|
||||
|
||||
if let Some(win) = handle.get_webview_window("login") {
|
||||
win.close()?;
|
||||
}
|
||||
|
||||
let win = tauri::WebviewWindowBuilder::new(
|
||||
&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 = credentials::finish(&code.clone(), flow).await?;
|
||||
|
||||
return Ok(Some(value));
|
||||
}
|
||||
}
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
|
||||
}
|
||||
|
||||
win.close()?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
use onelauncher_core::error::LauncherError;
|
||||
use serde::{Serialize, Serializer, ser::SerializeStruct};
|
||||
use specta::Type;
|
||||
|
||||
#[derive(thiserror::Error, Debug, Type)]
|
||||
#[serde(tag = "kind", content = "data")]
|
||||
pub enum SerializableError {
|
||||
#[error(transparent)]
|
||||
CoreError(#[serde(skip)] #[from] onelauncher_core::error::LauncherError),
|
||||
}
|
||||
|
||||
pub type SerializableResult<T> = std::result::Result<T, SerializableError>;
|
||||
|
||||
macro_rules! impl_serialize {
|
||||
($($variant:ident),* $(,)?) => {
|
||||
impl Serialize for SerializableError {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
match self {
|
||||
SerializableError::CoreError(error) => {
|
||||
display_tracing_error(error);
|
||||
|
||||
let mut state = serializer.serialize_struct("CoreError", 2)?;
|
||||
state.serialize_field("field_name", "CoreError")?;
|
||||
state.serialize_field("message", &error.to_string())?;
|
||||
state.end()
|
||||
}
|
||||
$(
|
||||
SerializableError::$variant(message) => {
|
||||
let mut state = serializer.serialize_struct(stringify!($variant), 2)?;
|
||||
state.serialize_field("field_name", stringify!($variant))?;
|
||||
state.serialize_field("message", &message.to_string())?;
|
||||
state.end()
|
||||
},
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_serialize! {}
|
||||
|
||||
pub fn display_tracing_error(err: &LauncherError) {
|
||||
match get_span_trace(err) {
|
||||
Some(span_trace) => {
|
||||
tracing::error!(error = %err, span_trace = %span_trace);
|
||||
}
|
||||
None => {
|
||||
tracing::error!(error = %err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_span_trace<'a>(
|
||||
error: &'a (dyn std::error::Error + 'static),
|
||||
) -> Option<&'a tracing_error::SpanTrace> {
|
||||
error.source().and_then(tracing_error::ExtractSpanTrace::span_trace)
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#[macro_export]
|
||||
macro_rules! collect_events {
|
||||
() => {{
|
||||
tauri_specta::collect_events! {
|
||||
onelauncher_core::api::proxy::event::LauncherEvent
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
@ -1,4 +1,2 @@
|
|||
pub mod commands;
|
||||
pub mod error;
|
||||
pub mod events;
|
||||
pub mod statics;
|
||||
|
|
|
|||
|
|
@ -1,117 +1,117 @@
|
|||
use onelauncher_core::store::Core;
|
||||
use tauri::plugin::TauriPlugin;
|
||||
use tauri::{Emitter, Runtime};
|
||||
use tauri_plugin_updater::{Update as TauriPluginUpdate, UpdaterExt};
|
||||
use tokio::sync::Mutex;
|
||||
// use onelauncher_core::store::Core;
|
||||
// use tauri::plugin::TauriPlugin;
|
||||
// use tauri::{Emitter, Runtime};
|
||||
// use tauri_plugin_updater::{Update as TauriPluginUpdate, UpdaterExt};
|
||||
// use tokio::sync::Mutex;
|
||||
|
||||
#[derive(Debug, Clone, specta::Type, serde::Serialize)]
|
||||
pub struct Update {
|
||||
pub version: String,
|
||||
}
|
||||
// #[derive(Debug, Clone, specta::Type, serde::Serialize)]
|
||||
// pub struct Update {
|
||||
// pub version: String,
|
||||
// }
|
||||
|
||||
impl Update {
|
||||
fn new(update: &TauriPluginUpdate) -> Self {
|
||||
Self {
|
||||
version: update.version.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl Update {
|
||||
// fn new(update: &TauriPluginUpdate) -> Self {
|
||||
// Self {
|
||||
// version: update.version.clone(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct State {
|
||||
install_lock: Mutex<()>,
|
||||
}
|
||||
// #[derive(Default)]
|
||||
// pub struct State {
|
||||
// install_lock: Mutex<()>,
|
||||
// }
|
||||
|
||||
async fn get_update(app: tauri::AppHandle) -> Result<Option<TauriPluginUpdate>, String> {
|
||||
app.updater_builder()
|
||||
.header("X-OneLauncher-Version", "stable")
|
||||
.map_err(|e| e.to_string())?
|
||||
.build()
|
||||
.map_err(|e| e.to_string())?
|
||||
.check()
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
// async fn get_update(app: tauri::AppHandle) -> Result<Option<TauriPluginUpdate>, String> {
|
||||
// app.updater_builder()
|
||||
// .header("X-OneLauncher-Version", "stable")
|
||||
// .map_err(|e| e.to_string())?
|
||||
// .build()
|
||||
// .map_err(|e| e.to_string())?
|
||||
// .check()
|
||||
// .await
|
||||
// .map_err(|e| e.to_string())
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, specta::Type, tauri_specta::Event)]
|
||||
#[serde(rename_all = "camelCase", tag = "status")]
|
||||
pub enum UpdateEvent {
|
||||
Loading,
|
||||
Error(String),
|
||||
UpdateAvailable { update: Update },
|
||||
NoUpdateAvailable,
|
||||
Installing,
|
||||
}
|
||||
// #[derive(Debug, Clone, serde::Serialize, specta::Type, tauri_specta::Event)]
|
||||
// #[serde(rename_all = "camelCase", tag = "status")]
|
||||
// pub enum UpdateEvent {
|
||||
// Loading,
|
||||
// Error(String),
|
||||
// UpdateAvailable { update: Update },
|
||||
// NoUpdateAvailable,
|
||||
// Installing,
|
||||
// }
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn check_for_update(app: tauri::AppHandle) -> Result<Option<Update>, String> {
|
||||
app.emit("updater", UpdateEvent::Loading).ok();
|
||||
// #[tauri::command]
|
||||
// #[specta::specta]
|
||||
// pub async fn check_for_update(app: tauri::AppHandle) -> Result<Option<Update>, String> {
|
||||
// app.emit("updater", UpdateEvent::Loading).ok();
|
||||
|
||||
let update = match get_update(app.clone()).await {
|
||||
Ok(update) => update,
|
||||
Err(e) => {
|
||||
app.emit("updater", UpdateEvent::Error(e.clone())).ok();
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
// let update = match get_update(app.clone()).await {
|
||||
// Ok(update) => update,
|
||||
// Err(e) => {
|
||||
// app.emit("updater", UpdateEvent::Error(e.clone())).ok();
|
||||
// return Err(e);
|
||||
// }
|
||||
// };
|
||||
|
||||
let update = update.map(|u| Update::new(&u));
|
||||
// let update = update.map(|u| Update::new(&u));
|
||||
|
||||
app.emit(
|
||||
"updater",
|
||||
update.clone().map_or(UpdateEvent::NoUpdateAvailable, |u| {
|
||||
UpdateEvent::UpdateAvailable { update: u }
|
||||
}),
|
||||
)
|
||||
.ok();
|
||||
// app.emit(
|
||||
// "updater",
|
||||
// update.clone().map_or(UpdateEvent::NoUpdateAvailable, |u| {
|
||||
// UpdateEvent::UpdateAvailable { update: u }
|
||||
// }),
|
||||
// )
|
||||
// .ok();
|
||||
|
||||
Ok(update)
|
||||
}
|
||||
// Ok(update)
|
||||
// }
|
||||
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn install_update(
|
||||
app: tauri::AppHandle,
|
||||
state: tauri::State<'_, State>,
|
||||
) -> Result<(), String> {
|
||||
let Ok(lock) = state.install_lock.try_lock() else {
|
||||
return Err("Update already installing".into());
|
||||
};
|
||||
// #[tauri::command]
|
||||
// #[specta::specta]
|
||||
// pub async fn install_update(
|
||||
// app: tauri::AppHandle,
|
||||
// state: tauri::State<'_, State>,
|
||||
// ) -> Result<(), String> {
|
||||
// let Ok(lock) = state.install_lock.try_lock() else {
|
||||
// return Err("Update already installing".into());
|
||||
// };
|
||||
|
||||
app.emit("updater", UpdateEvent::Installing).ok();
|
||||
// app.emit("updater", UpdateEvent::Installing).ok();
|
||||
|
||||
get_update(app.clone())
|
||||
.await?
|
||||
.ok_or_else(|| "No update required".to_string())?
|
||||
.download_and_install(|_, _| {}, || {})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
// get_update(app.clone())
|
||||
// .await?
|
||||
// .ok_or_else(|| "No update required".to_string())?
|
||||
// .download_and_install(|_, _| {}, || {})
|
||||
// .await
|
||||
// .map_err(|e| e.to_string())?;
|
||||
|
||||
drop(lock);
|
||||
// drop(lock);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
#[must_use]
|
||||
pub fn plugin<R: Runtime>() -> TauriPlugin<R> {
|
||||
tauri::plugin::Builder::new("onelauncher-updater")
|
||||
.on_page_load(|window, _| {
|
||||
#[cfg(target_os = "linux")]
|
||||
let updater_available = false;
|
||||
// #[must_use]
|
||||
// pub fn plugin<R: Runtime>() -> TauriPlugin<R> {
|
||||
// tauri::plugin::Builder::new("onelauncher-updater")
|
||||
// .on_page_load(|window, _| {
|
||||
// #[cfg(target_os = "linux")]
|
||||
// let updater_available = false;
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let updater_available = true;
|
||||
// #[cfg(not(target_os = "linux"))]
|
||||
// let updater_available = true;
|
||||
|
||||
if updater_available {
|
||||
window
|
||||
.eval("window.__LAUNCHER_UPDATER__ = true;")
|
||||
.expect("Failed to inject updater JS");
|
||||
}
|
||||
})
|
||||
.js_init_script(format!(
|
||||
r#"window.__ONELAUNCHER_VERSION__ = "{}";"#,
|
||||
Core::get().launcher_version,
|
||||
))
|
||||
.build()
|
||||
}
|
||||
// if updater_available {
|
||||
// window
|
||||
// .eval("window.__LAUNCHER_UPDATER__ = true;")
|
||||
// .expect("Failed to inject updater JS");
|
||||
// }
|
||||
// })
|
||||
// .js_init_script(format!(
|
||||
// r#"window.__ONELAUNCHER_VERSION__ = "{}";"#,
|
||||
// Core::get().launcher_version,
|
||||
// ))
|
||||
// .build()
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
use onelauncher_core::api::proxy::ProxyTauri;
|
||||
use onelauncher_core::api::tauri::{TauriLauncherEventApi, TauriLauncherApi};
|
||||
use onelauncher_core::error::LauncherResult;
|
||||
use onelauncher_core::store::proxy::ProxyState;
|
||||
use onelauncher_core::store::semaphore::SemaphoreStore;
|
||||
use onelauncher_core::store::{Core, CoreOptions, Dirs, State};
|
||||
use tauri::{Emitter, Manager};
|
||||
|
||||
use crate::api::commands::OneLauncherApi;
|
||||
|
||||
pub mod api;
|
||||
pub mod constants;
|
||||
pub mod ext;
|
||||
|
|
@ -38,19 +41,15 @@ async fn initialize_core() -> LauncherResult<()> {
|
|||
|
||||
#[tracing::instrument(skip_all)]
|
||||
async fn initialize_tauri(builder: tauri::Builder<tauri::Wry>) -> LauncherResult<tauri::App> {
|
||||
let prebuild = tauri_specta::Builder::<tauri::Wry>::new()
|
||||
.commands(collect_commands!())
|
||||
.events(collect_events!());
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
prebuild
|
||||
.export(
|
||||
let router = taurpc::Router::new()
|
||||
.export_config(
|
||||
specta_typescript::Typescript::default()
|
||||
.bigint(specta_typescript::BigIntExportBehavior::BigInt)
|
||||
.formatter(ext::specta::formatter),
|
||||
"../frontend/src/bindings.gen.ts",
|
||||
)
|
||||
.expect("failed to export debug bindings!");
|
||||
.merge(api::commands::OneLauncherApiImpl.into_handler())
|
||||
.merge(onelauncher_core::api::tauri::TauriLauncherApiImpl.into_handler())
|
||||
.merge(onelauncher_core::api::tauri::TauriLauncherEventApiImpl.into_handler());
|
||||
|
||||
let builder = builder
|
||||
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
|
||||
|
|
@ -60,15 +59,11 @@ async fn initialize_tauri(builder: tauri::Builder<tauri::Wry>) -> LauncherResult
|
|||
}))
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(ext::updater::plugin())
|
||||
.manage(ext::updater::State::default())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
// .plugin(api::init())
|
||||
.menu(tauri::menu::Menu::new)
|
||||
.invoke_handler(prebuild.invoke_handler())
|
||||
.invoke_handler(router.into_handler())
|
||||
.setup(move |app| {
|
||||
prebuild.mount_events(app.handle());
|
||||
setup_window(app.handle()).expect("failed to setup main window");
|
||||
Ok(())
|
||||
});
|
||||
|
|
@ -93,9 +88,11 @@ async fn initialize_state(handle: &tauri::AppHandle) -> LauncherResult<()> {
|
|||
|
||||
pub async fn run() {
|
||||
initialize_core().await.expect("failed to initialize core");
|
||||
|
||||
let app = initialize_tauri(tauri::Builder::default())
|
||||
.await
|
||||
.expect("failed to initialize tauri");
|
||||
|
||||
initialize_state(app.handle())
|
||||
.await
|
||||
.expect("failed to initialize state");
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@
|
|||
"tailwind-variants": "^1.0.0",
|
||||
"tailwindcss": "^4.0.6",
|
||||
"tailwindcss-animated": "^2.0.0",
|
||||
"tailwindcss-react-aria-components": "^2.0.0"
|
||||
"tailwindcss-react-aria-components": "^2.0.0",
|
||||
"taurpc": "^1.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tanstack/eslint-config": "^0.1.0",
|
||||
|
|
|
|||
|
|
@ -1,152 +1,65 @@
|
|||
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
|
||||
// This file has been generated by Specta. DO NOT EDIT.
|
||||
|
||||
/** user-defined commands */
|
||||
import type { InferCommandOutput } from 'taurpc';
|
||||
import { createTauRPCProxy as createProxy } from 'taurpc';
|
||||
|
||||
/** tauri-specta globals */
|
||||
type TAURI_CHANNEL<T> = (response: T) => void;
|
||||
|
||||
import type { WebviewWindow as __WebviewWindow__ } from '@tauri-apps/api/webviewWindow';
|
||||
import {
|
||||
invoke as TAURI_INVOKE,
|
||||
} from '@tauri-apps/api/core';
|
||||
import * as TAURI_API_EVENT from '@tauri-apps/api/event';
|
||||
|
||||
export const commands = {
|
||||
async getUsers(): Promise<Result<Array<MinecraftCredentials>, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_users') };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async getUser(uuid: string): Promise<Result<MinecraftCredentials, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_user', { uuid }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async removeUser(uuid: string): Promise<Result<null, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('remove_user', { uuid }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async getDefaultUser(fallback: boolean | null): Promise<Result<MinecraftCredentials | null, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_default_user', { fallback }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async setDefaultUser(uuid: string | null): Promise<Result<null, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('set_default_user', { uuid }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async beginMsFlow(): Promise<Result<MinecraftCredentials | null, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('begin_ms_flow') };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async createCluster(options: CreateCluster): Promise<Result<Model, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('create_cluster', { options }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async getClusters(): Promise<Result<Array<Model>, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_clusters') };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async getClusterById(id: bigint): Promise<Result<Model | null, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_cluster_by_id', { id }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async getGlobalProfile(): Promise<Result<SettingProfileModel, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_global_profile') };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async getProfileOrDefault(name: string | null): Promise<Result<SettingProfileModel, SerializableError>> {
|
||||
try {
|
||||
return { status: 'ok', data: await TAURI_INVOKE('get_profile_or_default', { name }) };
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof Error)
|
||||
throw e;
|
||||
else return { status: 'error', error: e as any };
|
||||
}
|
||||
},
|
||||
async openDevTools(): Promise<void> {
|
||||
await TAURI_INVOKE('open_dev_tools');
|
||||
},
|
||||
};
|
||||
|
||||
/** user-defined events */
|
||||
|
||||
export const events = __makeEvents__<{
|
||||
launcherEvent: LauncherEvent;
|
||||
}>({
|
||||
launcherEvent: 'launcher-event',
|
||||
});
|
||||
|
||||
/** user-defined constants */
|
||||
|
||||
/** user-defined types */
|
||||
export type ClusterError = { InvalidVersion: string } | 'MissingJavaVersion' | 'ClusterDownloading' | 'ClusterAlreadyRunning';
|
||||
|
||||
export type ClusterStage = 'notready' | 'downloading' | 'repairing' | 'ready';
|
||||
export interface CreateCluster { name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; icon_url: Icon | null }
|
||||
|
||||
export interface CreateCluster { name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; icon: Icon | null }
|
||||
|
||||
export type CryptoError = { InvalidHash: { algorithm: HashAlgorithm; expected: string; actual: string } } | 'InvalidAlgorithm';
|
||||
|
||||
export type DaoError = 'NotFound' | 'AlreadyExists' | { InvalidValue: [string, string] };
|
||||
|
||||
export type DirectoryError = 'BaseDir';
|
||||
|
||||
export type DiscordError = 'MissingClientId' | 'ConnectError';
|
||||
|
||||
export type GameLoader = 'vanilla' | 'forge' | 'neoforge' | 'quilt' | 'fabric' | 'legacyfabric';
|
||||
|
||||
export type HashAlgorithm = 'Sha1' | 'Sha256' | 'Md5';
|
||||
|
||||
/**
|
||||
* A wrapper around generic and unhelpful [`std::io::Error`] messages.
|
||||
*/
|
||||
export type IOError = { InvalidAbsolutePath: string } | { IOErrorWrapper: { path: string } } | 'IOError' | 'DeserializeError' | 'AsyncZipError';
|
||||
|
||||
export type Icon = string;
|
||||
|
||||
export type IncompatiblePackageType = 'McVersion' | 'Loader';
|
||||
|
||||
export type IngressError = 'NotFound';
|
||||
|
||||
export interface IngressPayload { id: string; message: string; ingress_type: IngressType; percent: number | null; total: number }
|
||||
|
||||
export type IngressType = { Download: { file_name: string } } | 'JavaPrepare' | 'JavaCheck' | 'JavaLocate' | 'MinecraftDownload' | { PrepareCluster: { cluster_name: string } };
|
||||
|
||||
export type JavaError = { ParseVersion: [string] } | 'Execute' | 'MissingJava';
|
||||
|
||||
export type LauncherError = { type: 'DirError'; data: DirectoryError } | { type: 'IOError'; data: IOError } | { type: 'IngressError'; data: IngressError } | { type: 'JavaError'; data: JavaError } | { type: 'CryptoError'; data: CryptoError } | { type: 'DiscordError'; data: DiscordError } | { type: 'MetadataError'; data: MetadataError } | { type: 'ClusterError'; data: ClusterError } | { type: 'MinecraftAuthError'; data: MinecraftAuthError } | { type: 'ProcessError'; data: ProcessError } | { type: 'PackageError'; data: PackageError } | { type: 'DaoError'; data: DaoError } | { type: 'SerdeError' } | { type: 'AnyhowError' } | { type: 'DbError' } | { type: 'ReqwestError' } | { type: 'InterpulseError' } | { type: 'RegexError' } | { type: 'SemaphoreError' } | { type: 'UrlError' } | { type: 'TauriError' };
|
||||
|
||||
export type LauncherEvent = { Ingress: IngressPayload } | { Message: MessagePayload } | { Process: ProcessPayload };
|
||||
|
||||
export type MessageLevel = 'Info' | 'Warn' | 'Error';
|
||||
|
||||
export interface MessagePayload { level: MessageLevel; message: string }
|
||||
|
||||
export type MetadataError = 'FetchError' | { NotModdedManifest: GameLoader } | { NotVanillaManifest: GameLoader } | 'ParseError' | 'NoMatchingLoader' | 'NoMatchingVersion';
|
||||
|
||||
/**
|
||||
* Wrapper around all `Error`s that can occur during the Microsoft authentication process.
|
||||
*/
|
||||
export type MinecraftAuthError = 'PublicKeyReading' | 'PKCS8Error' | { SerializeError: { step: MinecraftAuthStep } } | { DeserializeError: { step: MinecraftAuthStep; raw: string } } | { RequestError: { step: MinecraftAuthStep } } | { SigningError: { step: MinecraftAuthStep } } | 'HashError' | 'SessionIdError';
|
||||
|
||||
/**
|
||||
* An ordered list of all MSA authentication steps.
|
||||
*/
|
||||
export type MinecraftAuthStep = 'DeviceToken' | 'SisuAuthenicate' | 'OAuthToken' | 'RefreshOAuthToken' | 'SisuAuthorize' | 'XstsAuthorize' | 'MinecraftToken' | 'MinecraftEntitlements' | 'MinecraftProfile';
|
||||
|
||||
/**
|
||||
* A structure of all needed Minecraft credentials for logging in and account management.
|
||||
*/
|
||||
|
|
@ -173,61 +86,29 @@ export interface MinecraftCredentials {
|
|||
expires: string;
|
||||
|
||||
}
|
||||
|
||||
export interface Model { id: bigint; folder_name: string; stage: ClusterStage; created_at: string; group_id: bigint | null; name: string; mc_version: string; mc_loader: GameLoader; mc_loader_version: string | null; last_played: string | null; overall_played: bigint | null; icon_url: Icon | null; setting_profile_name: string | null; linked_pack_id: string | null; linked_pack_version: string | null }
|
||||
|
||||
export type PackageError = 'NoPrimaryFile' | 'IsModPack' | { Incompatible: IncompatiblePackageType };
|
||||
|
||||
export interface Process { pid: number; started_at: string; cluster_id: bigint; post_hook: string | null; account_id: string }
|
||||
|
||||
export type ProcessError = { HookUnsuccessful: number } | 'NoPid';
|
||||
|
||||
export type ProcessPayload = { Starting: { command: string } } | { Started: { process: Process } } | { Stopped: { pid: number; exit_code: number } } | { Output: { pid: number; output: string } };
|
||||
|
||||
export interface Resolution { width: number; height: number }
|
||||
export interface SerializableError { kind: 'CoreError' }
|
||||
|
||||
export interface SettingProfileModel { name: string; java_id: bigint | null; res: Resolution | null; force_fullscreen: boolean | null; mem_max: number | null; launch_args: string | null; launch_env: string | null; hook_pre: string | null; hook_wrapper: string | null; hook_post: string | null; os_extra: SettingsOsExtra | null }
|
||||
|
||||
export interface SettingsOsExtra { enable_gamemode: boolean | null }
|
||||
|
||||
interface __EventObj__<T> {
|
||||
listen: (
|
||||
cb: TAURI_API_EVENT.EventCallback<T>,
|
||||
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
|
||||
once: (
|
||||
cb: TAURI_API_EVENT.EventCallback<T>,
|
||||
) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
|
||||
emit: null extends T
|
||||
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
|
||||
: (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
|
||||
const ARGS_MAP = { 'onelauncher': '{"open_dev_tools":[],"return_error":[]}', '': '{"send_event":["event"]}', 'core': '{"get_clusters":[],"get_user":["uuid"],"remove_user":["uuid"],"create_cluster":["options"],"get_profile_or_default":["name"],"get_default_user":["fallback"],"set_default_user":["uuid"],"get_global_profile":[],"open_msa_login":[],"get_users":[],"get_cluster":["id"],"remove_cluster":["id"]}' };
|
||||
export interface Router {
|
||||
'onelauncher': { return_error: () => Promise<null>; open_dev_tools: () => Promise<void> };
|
||||
'': { send_event: (event: LauncherEvent) => Promise<void> };
|
||||
'core': { get_clusters: () => Promise<Array<Model>>; get_cluster: (id: bigint) => Promise<Model | null>; remove_cluster: (id: bigint) => Promise<null>; create_cluster: (options: CreateCluster) => Promise<Model>; get_profile_or_default: (name: string | null) => Promise<SettingProfileModel>; get_global_profile: () => Promise<SettingProfileModel>; get_users: () => Promise<Array<MinecraftCredentials>>; get_user: (uuid: string) => Promise<MinecraftCredentials | null>; remove_user: (uuid: string) => Promise<null>; get_default_user: (fallback: boolean | null) => Promise<MinecraftCredentials | null>; set_default_user: (uuid: string | null) => Promise<null>; open_msa_login: () => Promise<MinecraftCredentials | null> };
|
||||
}
|
||||
|
||||
export type Result<T, E> =
|
||||
| { status: 'ok'; data: T }
|
||||
| { status: 'error'; error: E };
|
||||
|
||||
function __makeEvents__<T extends Record<string, any>>(
|
||||
mappings: Record<keyof T, string>,
|
||||
) {
|
||||
return new Proxy(
|
||||
{} as unknown as {
|
||||
[K in keyof T]: __EventObj__<T[K]> & {
|
||||
(handle: __WebviewWindow__): __EventObj__<T[K]>;
|
||||
};
|
||||
},
|
||||
{
|
||||
get: (_, event) => {
|
||||
const name = mappings[event as keyof T];
|
||||
|
||||
return new Proxy((() => {}) as any, {
|
||||
apply: (_, __, [window]: [__WebviewWindow__]) => ({
|
||||
listen: (arg: any) => window.listen(name, arg),
|
||||
once: (arg: any) => window.once(name, arg),
|
||||
emit: (arg: any) => window.emit(name, arg),
|
||||
}),
|
||||
get: (_, command: keyof __EventObj__<any>) => {
|
||||
switch (command) {
|
||||
case 'listen':
|
||||
return (arg: any) => TAURI_API_EVENT.listen(name, arg);
|
||||
case 'once':
|
||||
return (arg: any) => TAURI_API_EVENT.once(name, arg);
|
||||
case 'emit':
|
||||
return (arg: any) => TAURI_API_EVENT.emit(name, arg);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
export type { InferCommandOutput };
|
||||
export const createTauRPCProxy = () => createProxy<Router>(ARGS_MAP);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import PlayerHead from './content/PlayerHead';
|
|||
import AccountPopup from './overlay/popups/AccountPopup';
|
||||
|
||||
function Navbar() {
|
||||
const defaultUser = useCommand('getDefaultUser', () => bindings.commands.getDefaultUser(false));
|
||||
const defaultUser = useCommand('getDefaultUser', () => bindings.core.get_default_user(false));
|
||||
|
||||
return (
|
||||
<div className="h-15 min-h-15 flex flex-row items-center *:flex-1">
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import { bindings } from "@/main";
|
||||
import useCommand from "./useCommand";
|
||||
import { useEffect, useState } from "react";
|
||||
import type { Model } from "@/bindings.gen";
|
||||
import type { Model } from '@/bindings.gen';
|
||||
import { bindings } from '@/main';
|
||||
import { useEffect, useState } from 'react';
|
||||
import useCommand from './useCommand';
|
||||
|
||||
function useRecentCluster() {
|
||||
const result = useCommand("getClusters", bindings.commands.getClusters);
|
||||
const result = useCommand('getClusters', bindings.core.get_clusters);
|
||||
const [cluster, setCluster] = useState<Model | undefined>();
|
||||
|
||||
useEffect(() => {
|
||||
if (!result.data) return;
|
||||
if (!result.data)
|
||||
return;
|
||||
|
||||
let mostRecentCluster: Model | undefined;
|
||||
|
||||
|
|
@ -23,13 +24,13 @@ function useRecentCluster() {
|
|||
|
||||
if (typeof currentPlayed !== 'string' && typeof newPlayed === 'string') {
|
||||
mostRecentCluster = c;
|
||||
} else if (typeof currentPlayed === 'string' && typeof newPlayed === 'string') {
|
||||
}
|
||||
else if (typeof currentPlayed === 'string' && typeof newPlayed === 'string') {
|
||||
const playedAt = new Date(currentPlayed);
|
||||
const clusterPlayedAt = new Date(newPlayed);
|
||||
|
||||
if (clusterPlayedAt > playedAt) {
|
||||
if (clusterPlayedAt > playedAt)
|
||||
mostRecentCluster = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -39,4 +40,4 @@ function useRecentCluster() {
|
|||
return cluster;
|
||||
}
|
||||
|
||||
export default useRecentCluster;
|
||||
export default useRecentCluster;
|
||||
|
|
|
|||
|
|
@ -1,22 +1,19 @@
|
|||
import type { Result } from '@/bindings.gen';
|
||||
import type { bindings } from '@/main';
|
||||
import type { UndefinedInitialDataOptions } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
type CacheKey = keyof typeof bindings.commands;
|
||||
type CacheKey = (keyof typeof bindings.core) | (keyof typeof bindings.onelauncher);
|
||||
|
||||
function useCommand<T, TError>(cacheKey: CacheKey | (string & {}), command: () => Promise<Result<T, TError>>, options?: Omit<UndefinedInitialDataOptions<T>, 'queryKey' | 'queryFn'>) {
|
||||
function useCommand<T>(cacheKey: CacheKey | (string & {}), command: () => Promise<T>, options?: Omit<UndefinedInitialDataOptions<T>, 'queryKey' | 'queryFn'>) {
|
||||
return useQuery({
|
||||
queryKey: [cacheKey],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const result = await command();
|
||||
if (result.status === 'error')
|
||||
return Promise.reject(result.error);
|
||||
|
||||
return result.data;
|
||||
return result;
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e);
|
||||
if (e instanceof Error)
|
||||
return Promise.reject(e);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -3,15 +3,17 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|||
import { createRouter, RouterProvider } from '@tanstack/react-router';
|
||||
import { StrictMode } from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { routeTree } from './routeTree.gen';
|
||||
import { createTauRPCProxy } from './bindings.gen';
|
||||
|
||||
import { routeTree } from './routeTree.gen';
|
||||
import './fonts';
|
||||
import './utils/nativeExperience';
|
||||
import './utils/devExperience';
|
||||
import 'overlayscrollbars/overlayscrollbars.css';
|
||||
import './styles/global.css';
|
||||
|
||||
export * as bindings from './bindings.gen';
|
||||
// Tauri bindings
|
||||
export const bindings = createTauRPCProxy();
|
||||
|
||||
// Tanstack Query Client
|
||||
const queryClient = new QueryClient({
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import DefaultBanner from '@/assets/images/default_banner.png';
|
||||
import type { Model } from '@/bindings.gen';
|
||||
import DefaultBanner from '@/assets/images/default_banner.png';
|
||||
import HeaderImage from '@/assets/images/default_banner.png';
|
||||
import DefaultInstancePhoto from '@/assets/images/default_instance_cover.jpg';
|
||||
import Button from '@/components/base/Button';
|
||||
import { TextField } from '@/components/base/TextField';
|
||||
import Modal from '@/components/overlay/Modal';
|
||||
import useCommand from '@/hooks/useCommand';
|
||||
import { bindings } from '@/main';
|
||||
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import DefaultInstancePhoto from "@/assets/images/default_instance_cover.jpg"
|
||||
import Modal from '@/components/overlay/Modal';
|
||||
import { Server01Icon } from '@untitled-theme/icons-react';
|
||||
import HeaderImage from "@/assets/images/default_banner.png";
|
||||
import { TextField } from '@/components/base/TextField';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
|
||||
export const Route = createFileRoute('/app/')({
|
||||
component: RouteComponent,
|
||||
|
|
@ -20,7 +20,11 @@ Please note this route has a very big issue related to scrolling
|
|||
and i am very angry rn so i will not be fixing it rn
|
||||
*/
|
||||
function RouteComponent() {
|
||||
const result = useCommand("getClusters", bindings.commands.getClusters)
|
||||
const result = useCommand('getClusters', bindings.core.get_clusters);
|
||||
const test = useCommand('ajgiagwo', bindings.onelauncher.return_error, {
|
||||
enabled: true,
|
||||
retry: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col gap-y-4 text-fg-primary">
|
||||
|
|
@ -32,7 +36,7 @@ function RouteComponent() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-col'>
|
||||
<div className="flex flex-col">
|
||||
<ClusterGroup clusters={result.data} isFetching={result.isFetching} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -111,25 +115,23 @@ function Banner() {
|
|||
}
|
||||
|
||||
function ClusterCreate() {
|
||||
const result = useCommand("createCluster", () => bindings.commands.createCluster({
|
||||
icon_url: "asd",
|
||||
mc_loader: "vanilla",
|
||||
mc_version: "1.20.1",
|
||||
name: "Test Cluster",
|
||||
mc_loader_version: "0.13.5",
|
||||
const result = useCommand('createCluster', () => bindings.commands.createCluster({
|
||||
icon_url: 'asd',
|
||||
mc_loader: 'vanilla',
|
||||
mc_version: '1.20.1',
|
||||
name: 'Test Cluster',
|
||||
mc_loader_version: '0.13.5',
|
||||
}), {
|
||||
enabled: false,
|
||||
subscribed: false
|
||||
})
|
||||
subscribed: false,
|
||||
});
|
||||
|
||||
const testThingy = () => {
|
||||
result.refetch()
|
||||
result.refetch();
|
||||
|
||||
if (result.isError) {
|
||||
alert(result.error.message)
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (result.isError)
|
||||
alert(result.error.message);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -157,13 +159,13 @@ function ClusterCreate() {
|
|||
</div>
|
||||
<div className="flex flex-col border border-white/5 rounded-b-lg">
|
||||
<div className="p-3">
|
||||
<TextField placeholder='Epik cluster name' className={"px-2"} />
|
||||
<TextField className="px-2" placeholder="Epik cluster name" />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row justify-end gap-x-2 p-3 pt-0">
|
||||
<Button
|
||||
color="primary"
|
||||
children="Create"
|
||||
color="primary"
|
||||
onClick={testThingy}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -172,43 +174,44 @@ function ClusterCreate() {
|
|||
</Modal>
|
||||
</Modal.Trigger>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
interface ClusterGroupProps {
|
||||
clusters: Model[] | undefined;
|
||||
clusters: Array<Model> | undefined;
|
||||
isFetching?: boolean;
|
||||
}
|
||||
|
||||
function ClusterGroup(props: ClusterGroupProps) {
|
||||
if (props.isFetching) {
|
||||
if (props.isFetching)
|
||||
return (
|
||||
<div className='flex items-center justify-center h-full'>
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="w-8 h-8 border-4 border-brand rounded-full border-t-transparent animate-spin" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-full w-full">
|
||||
<OverlayScrollbarsComponent
|
||||
className="h-full w-full"
|
||||
>
|
||||
<div className='grid grid-cols-4 gap-4 max-h-96 2xl:grid-cols-6 pb-4'>
|
||||
{props.clusters?.map((data) => (
|
||||
<div className="grid grid-cols-4 gap-4 max-h-96 2xl:grid-cols-6 pb-4">
|
||||
{props.clusters?.map(data => (
|
||||
<ClusterCard key={data.id} {...data} />
|
||||
))}
|
||||
</div>
|
||||
</OverlayScrollbarsComponent>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function ClusterCard(props: Model) {
|
||||
return (
|
||||
<Link to='/app/cluster' search={{
|
||||
id: props.id
|
||||
}}>
|
||||
<Link
|
||||
search={{
|
||||
id: props.id,
|
||||
}} to="/app/cluster"
|
||||
>
|
||||
<div
|
||||
className="group relative h-[152px] flex flex-col rounded-xl border border-component-border/5 bg-component-bg active:bg-component-bg-pressed hover:bg-component-bg-hover"
|
||||
>
|
||||
|
|
@ -239,4 +242,4 @@ function ClusterCard(props: Model) {
|
|||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ path = "src/lib.rs"
|
|||
default = [ "tauri" ]
|
||||
tauri = [
|
||||
"dep:tauri",
|
||||
"dep:tauri-specta",
|
||||
"dep:taurpc",
|
||||
"specta",
|
||||
"gui",
|
||||
"onelauncher_macro/tauri",
|
||||
|
|
@ -97,7 +97,7 @@ sanitize-filename = { workspace = true }
|
|||
|
||||
# features[tauri]
|
||||
tauri = { workspace = true, optional = true }
|
||||
tauri-specta = { workspace = true, optional = true }
|
||||
taurpc = { workspace = true, optional = true }
|
||||
|
||||
# features[specta]
|
||||
specta = { workspace = true, optional = true }
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use onelauncher_entity::{clusters, java_versions};
|
|||
use onelauncher_entity::icon::Icon;
|
||||
use onelauncher_entity::loader::GameLoader;
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use serde::Serialize;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::api::game::arguments;
|
||||
|
|
@ -24,7 +25,8 @@ pub use sync::*;
|
|||
|
||||
use super::ingress::init_ingress;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum ClusterError {
|
||||
#[error("version '{0}' was not found")]
|
||||
InvalidVersion(String),
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ pub async fn get_default_user() -> LauncherResult<Option<uuid::Uuid>> {
|
|||
#[tracing::instrument]
|
||||
pub async fn set_default_user(user: Option<uuid::Uuid>) -> LauncherResult<()> {
|
||||
let user = match user {
|
||||
Some(user) => Some(get_user(user).await?.id),
|
||||
Some(user) => get_user(user).await?.map(|user| user.id),
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ pub async fn remove_user(user: uuid::Uuid) -> LauncherResult<()> {
|
|||
|
||||
/// Get a list of user [`MinecraftCredentials`].
|
||||
#[tracing::instrument]
|
||||
pub async fn users() -> LauncherResult<Vec<MinecraftCredentials>> {
|
||||
pub async fn get_users() -> LauncherResult<Vec<MinecraftCredentials>> {
|
||||
let state = State::get().await?;
|
||||
let store = state.credentials.read().await;
|
||||
|
||||
|
|
@ -73,15 +73,14 @@ pub async fn users() -> LauncherResult<Vec<MinecraftCredentials>> {
|
|||
/// Get a specifc user's [`MinecraftCredentials`] by their [`uuid::Uuid`].
|
||||
/// Use [`crate::store::MinecraftState#refresh`] instead.
|
||||
#[tracing::instrument]
|
||||
pub async fn get_user(user: uuid::Uuid) -> LauncherResult<MinecraftCredentials> {
|
||||
pub async fn get_user(user: uuid::Uuid) -> LauncherResult<Option<MinecraftCredentials>> {
|
||||
let state = State::get().await?;
|
||||
let store = state.credentials.read().await;
|
||||
|
||||
let user = store
|
||||
.users
|
||||
.get(&user)
|
||||
.ok_or_else(|| anyhow::anyhow!("failed to get nonexistent user with uuid {user}"))?
|
||||
.clone();
|
||||
.cloned();
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ use crate::utils::io;
|
|||
|
||||
pub mod dao;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum JavaError {
|
||||
#[error("failed to parse version '{0}'")]
|
||||
ParseVersion(String, #[source] std::num::ParseIntError),
|
||||
ParseVersion(String, #[source] #[serde(skip)] std::num::ParseIntError),
|
||||
#[error("failed to execute java command")]
|
||||
Execute(#[from] std::io::Error),
|
||||
Execute(#[from] #[serde(skip)] std::io::Error),
|
||||
#[error("no java installations found")]
|
||||
MissingJava,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,3 +7,6 @@ pub mod packages;
|
|||
pub mod processes;
|
||||
pub mod proxy;
|
||||
pub mod setting_profiles;
|
||||
|
||||
#[cfg(feature = "tauri")]
|
||||
pub mod tauri;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use onelauncher_entity::icon::Icon;
|
|||
use onelauncher_entity::package::PackageType;
|
||||
use onelauncher_entity::{clusters, packages};
|
||||
use reqwest::Method;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::error::{LauncherError, LauncherResult};
|
||||
use crate::store::Dirs;
|
||||
|
|
@ -18,7 +19,8 @@ pub mod provider;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum PackageError {
|
||||
#[error("no file marked for download")]
|
||||
NoPrimaryFile,
|
||||
|
|
@ -28,7 +30,8 @@ pub enum PackageError {
|
|||
Incompatible(#[from] IncompatiblePackageType),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum IncompatiblePackageType {
|
||||
#[error("package is not compatible with the current version")]
|
||||
McVersion,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use serde::Serialize;
|
|||
|
||||
use crate::{error::LauncherResult, store::proxy::ProxyState};
|
||||
|
||||
#[onelauncher_macro::specta(event)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub enum LauncherEvent {
|
||||
Ingress(crate::api::ingress::IngressPayload),
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
use tauri::{AppHandle, Emitter, Manager};
|
||||
use tauri_specta::Event;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tracing::{error, warn};
|
||||
|
||||
use crate::{api::proxy::{event::LauncherEvent, LauncherProxy, message::MessageLevel}, LauncherResult};
|
||||
use crate::{api::{proxy::{event::LauncherEvent, message::MessageLevel, LauncherProxy}, tauri::LauncherEventEmitter}, LauncherResult};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProxyTauri {
|
||||
emitter: LauncherEventEmitter<tauri::Wry>,
|
||||
handle: AppHandle,
|
||||
}
|
||||
|
||||
impl ProxyTauri {
|
||||
#[must_use]
|
||||
pub const fn new(handle: AppHandle) -> Self {
|
||||
pub fn new(handle: AppHandle) -> Self {
|
||||
Self {
|
||||
handle
|
||||
emitter: LauncherEventEmitter::new(handle.clone()),
|
||||
handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,9 +30,7 @@ impl LauncherProxy for ProxyTauri {
|
|||
}
|
||||
}
|
||||
|
||||
self.handle
|
||||
.emit(LauncherEvent::NAME, event)
|
||||
.map_err(Into::into)
|
||||
Ok(self.emitter.send_event(event)?)
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
|
|
|
|||
167
packages/core/src/api/tauri/commands.rs
Normal file
167
packages/core/src/api/tauri/commands.rs
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
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
|
||||
async fn get_clusters() -> LauncherResult<Vec<Cluster>>;
|
||||
async fn get_cluster(id: ClusterId) -> LauncherResult<Option<Cluster>>;
|
||||
async fn remove_cluster(id: ClusterId) -> LauncherResult<()>;
|
||||
async fn create_cluster(options: CreateCluster) -> LauncherResult<Cluster>;
|
||||
|
||||
// Setting Profiles
|
||||
async fn get_profile_or_default(name: Option<String>) -> LauncherResult<SettingsProfile>;
|
||||
async fn get_global_profile() -> SettingsProfile;
|
||||
|
||||
// Users
|
||||
async fn get_users() -> LauncherResult<Vec<MinecraftCredentials>>;
|
||||
async fn get_user(uuid: uuid::Uuid) -> LauncherResult<Option<MinecraftCredentials>>;
|
||||
async fn remove_user(uuid: uuid::Uuid) -> LauncherResult<()>;
|
||||
async fn get_default_user(fallback: Option<bool>) -> LauncherResult<Option<MinecraftCredentials>>;
|
||||
async fn set_default_user(uuid: Option<uuid::Uuid>) -> LauncherResult<()>;
|
||||
async fn open_msa_login<R: Runtime>(app_handle: AppHandle<R>) -> LauncherResult<Option<MinecraftCredentials>>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, specta::Type, Clone)]
|
||||
pub struct CreateCluster {
|
||||
name: String,
|
||||
mc_version: String,
|
||||
mc_loader: GameLoader,
|
||||
mc_loader_version: Option<String>,
|
||||
icon: Option<Icon>,
|
||||
}
|
||||
|
||||
|
||||
#[taurpc::ipc_type]
|
||||
pub struct TauriLauncherApiImpl;
|
||||
|
||||
#[taurpc::resolvers]
|
||||
impl TauriLauncherApi for TauriLauncherApiImpl {
|
||||
async fn get_clusters(self) -> LauncherResult<Vec<Cluster>> {
|
||||
api::cluster::dao::get_all_clusters().await
|
||||
}
|
||||
|
||||
async fn get_cluster(self, id: ClusterId) -> LauncherResult<Option<Cluster>> {
|
||||
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<Cluster> {
|
||||
let cluster = api::cluster::create_cluster(&options.name, &options.mc_version, options.mc_loader, options.mc_loader_version.as_deref(), options.icon).await?;
|
||||
|
||||
// if api::setting_profiles::dao::get_profile_by_name(&options.name).await?.is_none() {
|
||||
// api::setting_profiles::create_profile(&options.name, async |mut profile| {
|
||||
// profile.mem_max = sea_orm::ActiveValue::Set(Some(2048));
|
||||
// Ok(profile)
|
||||
// }).await?;
|
||||
// }
|
||||
|
||||
Ok(cluster)
|
||||
}
|
||||
|
||||
async fn get_profile_or_default(self, name: Option<String>) -> LauncherResult<SettingsProfile> {
|
||||
api::setting_profiles::dao::get_profile_or_default(name.as_ref()).await
|
||||
}
|
||||
|
||||
async fn get_global_profile(self) -> SettingsProfile {
|
||||
api::setting_profiles::get_global_profile().await
|
||||
}
|
||||
|
||||
async fn get_users(self) -> LauncherResult<Vec<MinecraftCredentials>> {
|
||||
api::credentials::get_users().await
|
||||
}
|
||||
|
||||
async fn get_user(self, uuid: uuid::Uuid) -> LauncherResult<Option<MinecraftCredentials>> {
|
||||
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<bool>) -> LauncherResult<Option<MinecraftCredentials>> {
|
||||
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<uuid::Uuid>) -> LauncherResult<()> {
|
||||
api::credentials::set_default_user(uuid).await
|
||||
}
|
||||
|
||||
async fn open_msa_login<R: Runtime>(self, app_handle: AppHandle<R>) -> LauncherResult<Option<MinecraftCredentials>> {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
13
packages/core/src/api/tauri/events.rs
Normal file
13
packages/core/src/api/tauri/events.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use crate::api::proxy::event::LauncherEvent;
|
||||
|
||||
#[taurpc::procedures(event_trigger = LauncherEventEmitter)]
|
||||
pub trait TauriLauncherEventApi {
|
||||
#[taurpc(event)]
|
||||
async fn send_event(event: LauncherEvent);
|
||||
}
|
||||
|
||||
#[taurpc::ipc_type]
|
||||
pub struct TauriLauncherEventApiImpl;
|
||||
|
||||
#[taurpc::resolvers]
|
||||
impl TauriLauncherEventApi for TauriLauncherEventApiImpl {}
|
||||
5
packages/core/src/api/tauri/mod.rs
Normal file
5
packages/core/src/api/tauri/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod events;
|
||||
pub use events::*;
|
||||
|
||||
mod commands;
|
||||
pub use commands::*;
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
#[derive(thiserror::Error, Debug)]
|
||||
use serde::Serialize;
|
||||
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(thiserror::Error, Debug, Serialize)]
|
||||
#[serde(tag = "type", content = "data")]
|
||||
pub enum LauncherError {
|
||||
#[error(transparent)]
|
||||
DirError(#[from] crate::store::DirectoryError),
|
||||
|
|
@ -26,30 +30,41 @@ pub enum LauncherError {
|
|||
DaoError(#[from] DaoError),
|
||||
|
||||
#[error("json error: {0}")]
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
SerdeError(#[from] #[serde(skip)] serde_json::Error),
|
||||
#[error(transparent)]
|
||||
AnyhowError(#[from] anyhow::Error),
|
||||
AnyhowError(#[from] #[serde(skip)] anyhow::Error),
|
||||
#[error("database error: {0}")]
|
||||
DbError(#[from] sea_orm::DbErr),
|
||||
DbError(#[from] #[serde(skip)] sea_orm::DbErr),
|
||||
#[error("http error: {0}")]
|
||||
ReqwestError(#[from] reqwest::Error),
|
||||
ReqwestError(#[from] #[serde(skip)] reqwest::Error),
|
||||
#[error("meta error: {0}")]
|
||||
InterpulseError(#[from] interpulse::Error),
|
||||
InterpulseError(#[from] #[serde(skip)] interpulse::Error),
|
||||
#[error(transparent)]
|
||||
RegexError(#[from] regex::Error),
|
||||
RegexError(#[from] #[serde(skip)] regex::Error),
|
||||
#[error("couldn't acquire semaphore: {0}")]
|
||||
SemaphoreError(#[from] tokio::sync::AcquireError),
|
||||
SemaphoreError(#[from] #[serde(skip)] tokio::sync::AcquireError),
|
||||
#[error(transparent)]
|
||||
UrlError(#[from] url::ParseError),
|
||||
UrlError(#[from] #[serde(skip)] url::ParseError),
|
||||
|
||||
#[cfg(feature = "tauri")]
|
||||
#[error(transparent)]
|
||||
TauriError(#[from] tauri::Error),
|
||||
TauriError(#[from] #[serde(skip)] tauri::Error),
|
||||
}
|
||||
|
||||
// impl serde::Serialize for LauncherError {
|
||||
// fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
// where
|
||||
// S: serde::Serializer,
|
||||
// {
|
||||
// // Serialize the error as a string
|
||||
// serializer.serialize_str(&self.to_string())
|
||||
// }
|
||||
// }
|
||||
|
||||
pub type LauncherResult<T> = Result<T, LauncherError>;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(thiserror::Error, Debug, Serialize)]
|
||||
pub enum DaoError {
|
||||
#[error("entity was not found")]
|
||||
NotFound,
|
||||
|
|
|
|||
|
|
@ -1010,17 +1010,19 @@ pub enum MinecraftAuthStep {
|
|||
}
|
||||
|
||||
/// Wrapper around all `Error`s that can occur during the Microsoft authentication process.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(thiserror::Error, Debug, Serialize)]
|
||||
pub enum MinecraftAuthError {
|
||||
#[error("failed to read public key during key generation")]
|
||||
PublicKeyReading,
|
||||
#[error("failed to serialize private key using PKCS8: {0}")]
|
||||
PKCS8Error(#[from] p256::pkcs8::Error),
|
||||
PKCS8Error(#[from] #[serde(skip)] p256::pkcs8::Error),
|
||||
#[error("failed to serialize JSON during MSA step {step:?}: {source}")]
|
||||
SerializeError {
|
||||
step: MinecraftAuthStep,
|
||||
|
||||
#[source]
|
||||
#[serde(skip)]
|
||||
source: serde_json::Error,
|
||||
},
|
||||
#[error(
|
||||
|
|
@ -1031,20 +1033,24 @@ pub enum MinecraftAuthError {
|
|||
raw: String,
|
||||
|
||||
#[source]
|
||||
#[serde(skip)]
|
||||
source: serde_json::Error,
|
||||
|
||||
#[serde(skip)]
|
||||
status_code: reqwest::StatusCode,
|
||||
},
|
||||
#[error("failed to request using HTTP during MSA step {step:?}: {source}")]
|
||||
RequestError {
|
||||
step: MinecraftAuthStep,
|
||||
#[source]
|
||||
#[serde(skip)]
|
||||
source: reqwest::Error,
|
||||
},
|
||||
#[error("failed to create signed buffer during MSA step {step:?}: {source}")]
|
||||
SigningError {
|
||||
step: MinecraftAuthStep,
|
||||
#[source]
|
||||
#[serde(skip)]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("failed to read user hash")]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{path::PathBuf, time::Duration};
|
|||
use onelauncher_migration::MigratorTrait;
|
||||
use sea_orm::{ConnectOptions, Database, DatabaseConnection};
|
||||
|
||||
use crate::{utils::io::{self, IOError}, LauncherResult};
|
||||
use crate::{utils::io::IOError, LauncherResult};
|
||||
|
||||
use super::Dirs;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use onelauncher_entity::package::{PackageType, Provider};
|
||||
use serde::Serialize;
|
||||
use tokio::sync::OnceCell;
|
||||
|
||||
use crate::{utils, LauncherResult};
|
||||
|
|
@ -15,7 +16,8 @@ pub struct Dirs {
|
|||
base_dir: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum DirectoryError {
|
||||
#[error("Failed to get the base directory for the launcher.")]
|
||||
BaseDir,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
|
||||
use discord_rich_presence::{activity::{Activity, Assets, Button, Timestamps}, DiscordIpc, DiscordIpcClient};
|
||||
use serde::Serialize;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::error::LauncherResult;
|
||||
|
|
@ -106,7 +107,8 @@ impl DiscordRPC {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum DiscordError {
|
||||
#[error("Discord client ID is missing")]
|
||||
MissingClientId,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
|
@ -15,7 +15,8 @@ pub struct IngressProcessor {
|
|||
ingress_feeds: RwLock<HashMap<Uuid, Ingress>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum IngressError {
|
||||
#[error("ingress not found")]
|
||||
NotFound,
|
||||
|
|
@ -113,8 +114,8 @@ pub struct Ingress {
|
|||
pub last_sent: f64,
|
||||
}
|
||||
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
// #[onelauncher_macro::specta]
|
||||
#[derive(Serialize, Deserialize, specta::Type, Debug, Clone)]
|
||||
pub enum IngressType {
|
||||
Download { file_name: String },
|
||||
JavaPrepare,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ struct MetadataInner {
|
|||
// legacyfabric: Option<ModdedManifest>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum MetadataError {
|
||||
#[error("failed to fetch metadata")]
|
||||
FetchError,
|
||||
|
|
@ -39,8 +40,8 @@ pub enum MetadataError {
|
|||
NotModdedManifest(GameLoader),
|
||||
#[error("loader {0} does not use a vanilla manifest")]
|
||||
NotVanillaManifest(GameLoader),
|
||||
#[error("failed to parse metadata")]
|
||||
ParseError(#[from] serde_json::Error),
|
||||
#[error("failed to parse metadata: {0}")]
|
||||
ParseError(#[from] #[serde(skip)] serde_json::Error),
|
||||
#[error("no matching loader found")]
|
||||
NoMatchingLoader,
|
||||
#[error("no matching version found")]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ use crate::utils::io::IOError;
|
|||
use super::State;
|
||||
use super::credentials::MinecraftCredentials;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum ProcessError {
|
||||
#[error("launch hook exited with non-zero code {0}")]
|
||||
HookUnsuccessful(i32),
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ use std::io::Read;
|
|||
use std::str::FromStr;
|
||||
|
||||
use digest::DynDigest;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
||||
use super::io::IOError;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum CryptoError {
|
||||
#[error("expected {algorithm} hash {expected}, but got {actual}")]
|
||||
InvalidHash {
|
||||
|
|
@ -19,7 +21,8 @@ pub enum CryptoError {
|
|||
InvalidAlgorithm,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum HashAlgorithm {
|
||||
Sha1,
|
||||
Sha256,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
|||
use tokio_util::compat::TokioAsyncWriteCompatExt;
|
||||
|
||||
/// A wrapper around generic and unhelpful [`std::io::Error`] messages.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, thiserror::Error, Serialize)]
|
||||
pub enum IOError {
|
||||
#[error("invalid absolute path '{0}'")]
|
||||
InvalidAbsolutePath(PathBuf),
|
||||
|
|
@ -19,15 +20,16 @@ pub enum IOError {
|
|||
#[error("error acessing path: {source}, path: {path}")]
|
||||
IOErrorWrapper {
|
||||
#[source]
|
||||
#[serde(skip)]
|
||||
source: std::io::Error,
|
||||
path: String,
|
||||
},
|
||||
#[error(transparent)]
|
||||
IOError(#[from] std::io::Error),
|
||||
IOError(#[from] #[serde(skip)] std::io::Error),
|
||||
#[error("json deserialization error: {0}")]
|
||||
DeserializeError(#[from] serde_json::Error),
|
||||
DeserializeError(#[from] #[serde(skip)] serde_json::Error),
|
||||
#[error(transparent)]
|
||||
AsyncZipError(#[from] async_zip::error::ZipError),
|
||||
AsyncZipError(#[from] #[serde(skip)] async_zip::error::ZipError),
|
||||
}
|
||||
|
||||
impl<P: AsRef<std::path::Path>> From<(P, std::io::Error)> for IOError {
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ path = "src/lib.rs"
|
|||
[features]
|
||||
default = []
|
||||
specta = [
|
||||
"onelauncher_macro/specta",
|
||||
"dep:specta",
|
||||
"onelauncher_macro/specta",
|
||||
"interpulse/specta"
|
||||
]
|
||||
|
||||
|
|
@ -33,3 +33,6 @@ url = { workspace = true }
|
|||
interpulse = { workspace = true }
|
||||
merge = { workspace = true }
|
||||
specta = { workspace = true, optional = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use sea_orm::{sea_query::{self, Nullable, ValueType}, TryGetableFromJson};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
cfg_match! {
|
||||
cfg_select! {
|
||||
target_os = "windows" => {
|
||||
#[onelauncher_macro::specta]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(cfg_match)]
|
||||
#![feature(cfg_select)]
|
||||
|
||||
mod entities;
|
||||
mod domain;
|
||||
|
|
|
|||
|
|
@ -24,3 +24,6 @@ specta = []
|
|||
syn = { workspace = true }
|
||||
quote = { workspace = true }
|
||||
proc-macro2 = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{meta::ParseNestedMeta, parse_macro_input, Item};
|
||||
|
||||
|
|
@ -8,28 +9,17 @@ pub fn specta(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> p
|
|||
|
||||
let input = parse_macro_input!(item as Item);
|
||||
|
||||
let specta_event_type = if attrs.event {
|
||||
quote! {
|
||||
#[cfg_attr(feature = "tauri", derive(tauri_specta::Event))]
|
||||
}
|
||||
} else {
|
||||
proc_macro2::TokenStream::new()
|
||||
};
|
||||
|
||||
let specta_type = if let Some(rename) = attrs.rename {
|
||||
let specta_rename = if let Some(rename) = attrs.rename {
|
||||
quote! {
|
||||
#[cfg_attr(feature = "specta", derive(specta::Type))]
|
||||
#[cfg_attr(feature = "specta", specta(rename = #rename))]
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#[cfg_attr(feature = "specta", derive(specta::Type))]
|
||||
}
|
||||
TokenStream::new()
|
||||
};
|
||||
|
||||
let expanded = quote! {
|
||||
#specta_event_type
|
||||
#specta_type
|
||||
#[cfg_attr(feature = "specta", derive(specta::Type))]
|
||||
#specta_rename
|
||||
#input
|
||||
};
|
||||
|
||||
|
|
@ -38,15 +28,12 @@ pub fn specta(attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> p
|
|||
|
||||
#[derive(Default)]
|
||||
struct SpectaAttributes {
|
||||
event: bool,
|
||||
rename: Option<String>,
|
||||
}
|
||||
|
||||
impl SpectaAttributes {
|
||||
fn parse(&mut self, meta: ParseNestedMeta) -> syn::Result<()> {
|
||||
if meta.path.is_ident("event") {
|
||||
self.event = true;
|
||||
} else if meta.path.is_ident("rename") {
|
||||
if meta.path.is_ident("rename") {
|
||||
self.rename = Some(meta.value()?.to_string());
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
20
pnpm-lock.yaml
generated
20
pnpm-lock.yaml
generated
|
|
@ -73,6 +73,16 @@ importers:
|
|||
specifier: ^0.38.2
|
||||
version: 0.38.2
|
||||
|
||||
apps/oneclient/desktop:
|
||||
dependencies:
|
||||
'@oneclient/frontend':
|
||||
specifier: workspace:*
|
||||
version: link:../frontend
|
||||
devDependencies:
|
||||
'@tauri-apps/cli':
|
||||
specifier: ^2.0.4
|
||||
version: 2.5.0
|
||||
|
||||
apps/oneclient/frontend:
|
||||
dependencies:
|
||||
'@fontsource/poppins':
|
||||
|
|
@ -263,6 +273,9 @@ importers:
|
|||
tailwindcss-react-aria-components:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(tailwindcss@4.1.5)
|
||||
taurpc:
|
||||
specifier: ^1.8.1
|
||||
version: 1.8.1
|
||||
devDependencies:
|
||||
'@tanstack/eslint-config':
|
||||
specifier: ^0.1.0
|
||||
|
|
@ -4462,6 +4475,9 @@ packages:
|
|||
tar-stream@3.1.7:
|
||||
resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
|
||||
|
||||
taurpc@1.8.1:
|
||||
resolution: {integrity: sha512-qfR1ekhXApjbnWAqyE5qpDa/oMmKBwjNNDuqjYn7sO+ChI5qwQ4J/fS+00dVLE3I0lbZDizyY8ObSFBz3MRerQ==}
|
||||
|
||||
text-decoder@1.1.1:
|
||||
resolution: {integrity: sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==}
|
||||
|
||||
|
|
@ -9934,6 +9950,10 @@ snapshots:
|
|||
fast-fifo: 1.3.2
|
||||
streamx: 2.19.0
|
||||
|
||||
taurpc@1.8.1:
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.5.0
|
||||
|
||||
text-decoder@1.1.1:
|
||||
dependencies:
|
||||
b4a: 1.6.6
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue