diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..1f64a473 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 82f51e21..ce318a47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,6 @@ members = [ "core", "debugger", "desktop/src-tauri", - "testing", ] [workspace.package] @@ -33,7 +32,7 @@ tauri-plugin-updater = { git = "https://github.com/tauri-apps/plugins-workspace" rspc = { version = "0.2.0", features = [ "specta2" ] } specta = { version = "=2.0.0-rc.12" } -tauri-specta = { version = "=2.0.0-rc.9", features = [ +tauri-specta = { version = "=2.0.0-rc.10", features = [ "javascript", "typescript" ] } diff --git a/core/Cargo.toml b/core/Cargo.toml index 1b3dfa49..c36a56f0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,12 +14,22 @@ authors = { workspace = true } default = [] # feature flag allowing us to interact with tauri (for loading animations, errors showing on gui, etc) # also allows us to compile onelauncher core without tauri -tauri = [ "dep:tauri" ] +tauri = [ + "dep:tauri", + "dep:tauri-specta", + "dep:specta" +] cli = [ "dep:indicatif" ] [dependencies] onelauncher_debug = { path = "../debugger" } + +# GUI-only deps tauri = { workspace = true, optional = true } +tauri-specta = { workspace = true, optional = true } +specta = { workspace = true, optional = true } + +# CLI-only deps indicatif = { workspace = true, optional = true } interpulse = { workspace = true } diff --git a/desktop/.gitignore b/desktop/.gitignore index b3bed89e..e0be417d 100644 --- a/desktop/.gitignore +++ b/desktop/.gitignore @@ -1,2 +1,3 @@ /dist-isolation /coverage +./src/bindings.ts diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index c0675306..60c8bb32 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -41,6 +41,9 @@ tauri-plugin-single-instance = { workspace = true } tauri-plugin-updater = { workspace = true } tauri-plugin-authenticator = { workspace = true } +tauri-specta = { workspace = true } +specta = { workspace = true } + tokio = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/desktop/src-tauri/src/api/commands.rs b/desktop/src-tauri/src/api/commands.rs new file mode 100644 index 00000000..4c3e5382 --- /dev/null +++ b/desktop/src-tauri/src/api/commands.rs @@ -0,0 +1,43 @@ +use tauri_specta::{Builder, ExportLanguage}; +use crate::api; + +#[macro_export] +macro_rules! collect_commands { + () => { + { + use crate::api::commands::*; + tauri_specta::ts::builder() + .commands(tauri_specta::collect_commands![ + initialize_state, + is_dev + ]) + } + }; +} + +pub fn test() -> Builder { + use crate::api::commands::*; + tauri_specta::ts::builder() + .commands(tauri_specta::collect_commands![ + initialize_state, + is_dev + ]) +} + +#[specta::specta] +#[tracing::instrument(skip_all)] +#[tauri::command] +pub async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> { + onelauncher::ProxyState::initialize(app).await?; + let s = onelauncher::State::get().await?; + onelauncher::State::update(); + + s.processor.write().await.restore().await?; + Ok(()) +} + +#[specta::specta] +#[tauri::command] +pub fn is_dev() -> bool { + cfg!(debug_assertions) +} \ No newline at end of file diff --git a/desktop/src-tauri/src/api/mod.rs b/desktop/src-tauri/src/api/mod.rs index 786c5af2..d67bc477 100644 --- a/desktop/src-tauri/src/api/mod.rs +++ b/desktop/src-tauri/src/api/mod.rs @@ -4,6 +4,8 @@ use tauri::plugin::TauriPlugin; use tauri::Manager; use tokio::sync::Mutex; +pub mod commands; + pub fn init() -> TauriPlugin { tauri::plugin::Builder::new("onelauncher") .setup(|app, _| { @@ -11,14 +13,31 @@ pub fn init() -> TauriPlugin { Ok(()) }) - .invoke_handler(tauri::generate_handler![]) .build() } pub type Result = std::result::Result; -#[derive(thiserror::Error, Debug)] +#[derive(thiserror::Error, Debug, Serialize, specta::Type)] pub enum OneLauncherSerializableError { + #[error("{0}")] + CommonError(String), +} + +impl From for OneLauncherSerializableError { + fn from(value: OneLauncherError) -> Self { + Self::CommonError(value.to_string()) + } +} + +impl From for OneLauncherSerializableError { + fn from(value: onelauncher::Error) -> Self { + Self::CommonError(value.to_string()) + } +} + +#[derive(thiserror::Error, Debug)] +pub enum OneLauncherError { #[error("{0}")] OneLauncher(#[from] onelauncher::Error), @@ -37,14 +56,14 @@ pub enum OneLauncherSerializableError { // (yoinked under MIT license) macro_rules! impl_serialize_err { ($($variant:ident),* $(,)?) => { - impl Serialize for OneLauncherSerializableError { + impl Serialize for OneLauncherError { fn serialize(&self, serializer: S) -> std::result::Result where S: Serializer, { use serde::ser::SerializeStruct; match self { - OneLauncherSerializableError::OneLauncher(onelauncher_error) => { + OneLauncherError::OneLauncher(onelauncher_error) => { $crate::error::display_tracing_error(onelauncher_error); let mut state = serializer.serialize_struct("OneLauncher", 2)?; @@ -53,7 +72,7 @@ macro_rules! impl_serialize_err { state.end() } $( - OneLauncherSerializableError::$variant(message) => { + OneLauncherError::$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())?; diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index cd9136c2..93a699ea 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -1,25 +1,10 @@ use tauri::Manager; +use crate::api::commands; pub mod api; pub mod error; pub mod ext; -// #[tracing::instrument(skip_all)] -// #[tauri::command] -// async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> { -// onelauncher::ProxyState::initialize(app).await?; -// let s = onelauncher::State::get().await?; -// onelauncher::State::update(); - -// s.processor.write().await.restore().await?; -// Ok(()) -// } - -#[tauri::command] -fn is_dev() -> bool { - cfg!(debug_assertions) -} - #[derive(Clone, serde::Serialize)] struct SingleInstancePayload { args: Vec, @@ -33,7 +18,7 @@ pub async fn run() { let _log_guard = onelauncher::start_logger(); tracing::info!("initialized tracing subscriber. loading onelauncher..."); - run_app(tauri::Builder::default(), |app| { + run_app(|app| { if let Err(err) = setup(app) { tracing::error!("failed to setup app: {:?}", err); } @@ -41,11 +26,10 @@ pub async fn run() { .await; } -pub async fn run_app) + Send + 'static>( - builder: tauri::Builder, +pub async fn run_app( setup: F, ) { - let builder = builder + let builder = tauri::Builder::default() .plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_single_instance::init(|app, argv, cwd| { println!("{}, {argv:?}, {cwd}", app.package_info().name); @@ -55,7 +39,7 @@ pub async fn run_app) + Send + ' .plugin(tauri_plugin_updater::Builder::new().build()) .plugin(ext::updater::plugin()) .manage(ext::updater::State::default()) - // .plugin(tauri_plugin_window_state::Builder::default().build()) + .plugin(tauri_plugin_window_state::Builder::default().build()) .menu(tauri::menu::Menu::new) .setup(move |app| { setup(app); @@ -64,10 +48,14 @@ pub async fn run_app) + Send + ' let builder = builder .plugin(api::init()) - .invoke_handler(tauri::generate_handler![ - // initialize_state, - is_dev, - ]); + .invoke_handler({ + let builder = commands::test(); + + #[cfg(debug_assertions)] + let builder = builder.path("../src/bindings.ts"); + + builder.build().unwrap() + }); let app = builder .build(tauri::tauri_build_context!()) diff --git a/desktop/src/bindings.ts b/desktop/src/bindings.ts new file mode 100644 index 00000000..0f5b5bcb --- /dev/null +++ b/desktop/src/bindings.ts @@ -0,0 +1,80 @@ + // This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. + + export const commands = { +async initializeState() : Promise> { +try { + return { status: "ok", data: await TAURI_INVOKE("initialize_state") }; +} catch (e) { + if(e instanceof Error) throw e; + else return { status: "error", error: e as any }; +} +}, +async isDev() : Promise { +return await TAURI_INVOKE("is_dev"); +} +} + + + +/** user-defined types **/ + +export type OneLauncherSerializableError = { CommonError: string } + +/** tauri-specta globals **/ + + import { invoke as TAURI_INVOKE } from "@tauri-apps/api/core"; +import * as TAURI_API_EVENT from "@tauri-apps/api/event"; +import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow"; + +type __EventObj__ = { + listen: ( + cb: TAURI_API_EVENT.EventCallback + ) => ReturnType>; + once: ( + cb: TAURI_API_EVENT.EventCallback + ) => ReturnType>; + emit: T extends null + ? (payload?: T) => ReturnType + : (payload: T) => ReturnType; +}; + +export type Result = + | { status: "ok"; data: T } + | { status: "error"; error: E }; + +function __makeEvents__>( + mappings: Record +) { + return new Proxy( + {} as unknown as { + [K in keyof T]: __EventObj__ & { + (handle: __WebviewWindow__): __EventObj__; + }; + }, + { + 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__) => { + 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); + } + }, + }); + }, + } + ); +} + + \ No newline at end of file