mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-09-21 13:18:08 +03:00
refactor(core): merge invoke items into single struct, allow ? (#1683)
This commit is contained in:
parent
152c755c47
commit
1d6f418129
@ -3,5 +3,5 @@
|
||||
---
|
||||
|
||||
Refactored the `Plugin` trait `initialize` and `extend_api` signatures.
|
||||
`initialize` now takes the `App` as first argument, and `extend_api` takes a `InvokeResolver` as last argument.
|
||||
`initialize` now takes the `App` as first argument, and `extend_api` takes an `Invoke` instead of `InvokeMessage`.
|
||||
This adds support to managed state on plugins.
|
||||
|
@ -2,4 +2,4 @@
|
||||
"tauri": patch
|
||||
---
|
||||
|
||||
Removes the `with_window` attribute on the `command` macro. Tauri now infers it using the `FromCommand` trait.
|
||||
Removes the `with_window` attribute on the `command` macro. Tauri now infers it using the `CommandArg` trait.
|
||||
|
@ -63,7 +63,7 @@ pub fn generate_command(function: ItemFn) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
let arg_name_ = arg_name.clone().unwrap();
|
||||
let arg_name_ = arg_name.unwrap();
|
||||
let arg_name_s = arg_name_.to_string();
|
||||
|
||||
let arg_type = match arg_type {
|
||||
@ -76,13 +76,14 @@ pub fn generate_command(function: ItemFn) -> TokenStream {
|
||||
}
|
||||
};
|
||||
|
||||
invoke_args.append_all(quote! {
|
||||
let #arg_name_ = match <#arg_type>::from_command(#fn_name_str, #arg_name_s, &message) {
|
||||
Ok(value) => value,
|
||||
Err(e) => return tauri::InvokeResponse::error(::tauri::Error::InvalidArgs(#fn_name_str, e).to_string())
|
||||
};
|
||||
let item = quote!(::tauri::command::CommandItem {
|
||||
name: #fn_name_str,
|
||||
key: #arg_name_s,
|
||||
message: &__message,
|
||||
});
|
||||
invoke_arg_names.push(arg_name_.clone());
|
||||
|
||||
invoke_args.append_all(quote!(let #arg_name_ = <#arg_type>::from_command(#item)?;));
|
||||
invoke_arg_names.push(arg_name_);
|
||||
invoke_arg_types.push(arg_type);
|
||||
}
|
||||
|
||||
@ -97,21 +98,19 @@ pub fn generate_command(function: ItemFn) -> TokenStream {
|
||||
// otherwise we wrap it with an `Ok()`, converting the return value to tauri::InvokeResponse
|
||||
// note that all types must implement `serde::Serialize`.
|
||||
let return_value = if returns_result {
|
||||
quote! {
|
||||
match #fn_name(#(#invoke_arg_names),*)#await_maybe {
|
||||
Ok(value) => ::core::result::Result::<_, ()>::Ok(value).into(),
|
||||
Err(e) => ::core::result::Result::<(), _>::Err(e).into(),
|
||||
}
|
||||
}
|
||||
quote!(::core::result::Result::Ok(#fn_name(#(#invoke_arg_names),*)#await_maybe?))
|
||||
} else {
|
||||
quote! { ::core::result::Result::<_, ()>::Ok(#fn_name(#(#invoke_arg_names),*)#await_maybe).into() }
|
||||
quote! { ::core::result::Result::<_, ::tauri::InvokeError>::Ok(#fn_name(#(#invoke_arg_names),*)#await_maybe) }
|
||||
};
|
||||
|
||||
// double underscore prefix temporary until underlying scoping issue is fixed (planned)
|
||||
quote! {
|
||||
#function
|
||||
#vis fn #fn_wrapper<P: ::tauri::Params>(message: ::tauri::InvokeMessage<P>, resolver: ::tauri::InvokeResolver<P>) {
|
||||
use ::tauri::command::FromCommand;
|
||||
resolver.respond_async(async move {
|
||||
|
||||
#vis fn #fn_wrapper<P: ::tauri::Params>(invoke: ::tauri::Invoke<P>) {
|
||||
use ::tauri::command::CommandArg;
|
||||
let ::tauri::Invoke { message: __message, resolver: __resolver } = invoke;
|
||||
__resolver.respond_async(async move {
|
||||
#invoke_args
|
||||
#return_value
|
||||
})
|
||||
@ -139,12 +138,12 @@ pub fn generate_handler(item: proc_macro::TokenStream) -> TokenStream {
|
||||
});
|
||||
|
||||
quote! {
|
||||
move |message, resolver| {
|
||||
let cmd = message.command().to_string();
|
||||
match cmd.as_str() {
|
||||
#(stringify!(#fn_names) => #fn_wrappers(message, resolver),)*
|
||||
move |invoke| {
|
||||
let cmd = invoke.message.command();
|
||||
match cmd {
|
||||
#(stringify!(#fn_names) => #fn_wrappers(invoke),)*
|
||||
_ => {
|
||||
resolver.reject(format!("command {} not found", cmd))
|
||||
invoke.resolver.reject(format!("command {} not found", cmd))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -4,297 +4,136 @@
|
||||
|
||||
//! Useful items for custom commands.
|
||||
|
||||
use crate::hooks::InvokeError;
|
||||
use crate::{InvokeMessage, Params};
|
||||
use serde::de::Visitor;
|
||||
use serde::Deserializer;
|
||||
|
||||
/// A [`Deserializer`] wrapper around [`Value::get`].
|
||||
///
|
||||
/// If the key doesn't exist, an error will be returned if the deserialized type is not expecting
|
||||
/// an optional item. If the key does exist, the value will be called with [`Value`]'s
|
||||
/// [`Deserializer`] implementation.
|
||||
struct KeyedValue<'de> {
|
||||
command: &'de str,
|
||||
key: &'de str,
|
||||
value: &'de serde_json::Value,
|
||||
/// Represents a custom command.
|
||||
pub struct CommandItem<'a, P: Params> {
|
||||
/// The name of the command, e.g. `handler` on `#[command] fn handler(value: u64)`
|
||||
pub name: &'static str,
|
||||
|
||||
/// The key of the command item, e.g. `value` on `#[command] fn handler(value: u64)`
|
||||
pub key: &'static str,
|
||||
|
||||
/// The [`InvokeMessage`] that was passed to this command.
|
||||
pub message: &'a InvokeMessage<P>,
|
||||
}
|
||||
|
||||
macro_rules! kv_value {
|
||||
($s:ident) => {{
|
||||
use serde::de::Error;
|
||||
/// Trait implemented by command arguments to derive a value from a [`CommandItem`].
|
||||
///
|
||||
/// # Command Arguments
|
||||
///
|
||||
/// A command argument is any type that represents an item parsable from a [`CommandItem`]. Most
|
||||
/// implementations will use the data stored in [`InvokeMessage`] since [`CommandItem`] is mostly a
|
||||
/// wrapper around it.
|
||||
///
|
||||
/// # Provided Implementations
|
||||
///
|
||||
/// Tauri implements [`CommandArg`] automatically for a number of types.
|
||||
/// * [`tauri::Window`]
|
||||
/// * [`tauri::State`]
|
||||
/// * `T where T: serde::Deserialize`
|
||||
/// * Any type that implements `Deserialize` can automatically be used as a [`CommandArg`].
|
||||
pub trait CommandArg<'de, P: Params>: Sized {
|
||||
/// Derives an instance of `Self` from the [`CommandItem`].
|
||||
///
|
||||
/// If the derivation fails, the corresponding message will be rejected using [`InvokeMessage#reject`].
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError>;
|
||||
}
|
||||
|
||||
match $s.value.get($s.key) {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Err(serde_json::Error::custom(format!(
|
||||
"command {} missing required key `{}`",
|
||||
$s.command, $s.key
|
||||
)))
|
||||
/// Automatically implement [`CommandArg`] for any type that can be deserialized.
|
||||
impl<'de, D: serde::Deserialize<'de>, P: Params> CommandArg<'de, P> for D {
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
let arg = command.key;
|
||||
Self::deserialize(command).map_err(|e| crate::Error::InvalidArgs(arg, e).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Pass the result of [`serde_json::Value::get`] into [`serde_json::Value`]'s deserializer.
|
||||
///
|
||||
/// Returns an error if the [`CommandItem`]'s key does not exist in the value.
|
||||
macro_rules! pass {
|
||||
($fn:ident, $($arg:ident: $argt:ty),+) => {
|
||||
fn $fn<V: Visitor<'de>>(self, $($arg: $argt),*) -> Result<V::Value, Self::Error> {
|
||||
use serde::de::Error;
|
||||
|
||||
match self.message.payload.get(self.key) {
|
||||
Some(value) => value.$fn($($arg),*),
|
||||
None => {
|
||||
Err(serde_json::Error::custom(format!(
|
||||
"command {} missing required key {}",
|
||||
self.name, self.key
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserializer<'de> for KeyedValue<'de> {
|
||||
/// A [`Deserializer`] wrapper around [`CommandItem`].
|
||||
///
|
||||
/// If the key doesn't exist, an error will be returned if the deserialized type is not expecting
|
||||
/// an optional item. If the key does exist, the value will be called with
|
||||
/// [`Value`](serde_json::Value)'s [`Deserializer`] implementation.
|
||||
impl<'de, P: Params> Deserializer<'de> for CommandItem<'de, P> {
|
||||
type Error = serde_json::Error;
|
||||
|
||||
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_any(visitor)
|
||||
}
|
||||
pass!(deserialize_any, visitor: V);
|
||||
pass!(deserialize_bool, visitor: V);
|
||||
pass!(deserialize_i8, visitor: V);
|
||||
pass!(deserialize_i16, visitor: V);
|
||||
pass!(deserialize_i32, visitor: V);
|
||||
pass!(deserialize_i64, visitor: V);
|
||||
pass!(deserialize_u8, visitor: V);
|
||||
pass!(deserialize_u16, visitor: V);
|
||||
pass!(deserialize_u32, visitor: V);
|
||||
pass!(deserialize_u64, visitor: V);
|
||||
pass!(deserialize_f32, visitor: V);
|
||||
pass!(deserialize_f64, visitor: V);
|
||||
pass!(deserialize_char, visitor: V);
|
||||
pass!(deserialize_str, visitor: V);
|
||||
pass!(deserialize_string, visitor: V);
|
||||
pass!(deserialize_bytes, visitor: V);
|
||||
pass!(deserialize_byte_buf, visitor: V);
|
||||
|
||||
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_bool(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_i8(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_i16(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_i32(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_i64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_u8(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_u16(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_u32(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_u64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_f32(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_f64(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_char(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_string(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_bytes(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_byte_buf(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
match self.value.get(self.key) {
|
||||
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
|
||||
match self.message.payload.get(self.key) {
|
||||
Some(value) => value.deserialize_option(visitor),
|
||||
None => visitor.visit_none(),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_unit(visitor)
|
||||
}
|
||||
pass!(deserialize_unit, visitor: V);
|
||||
pass!(deserialize_unit_struct, name: &'static str, visitor: V);
|
||||
pass!(deserialize_newtype_struct, name: &'static str, visitor: V);
|
||||
pass!(deserialize_seq, visitor: V);
|
||||
pass!(deserialize_tuple, len: usize, visitor: V);
|
||||
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_unit_struct(name, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_newtype_struct(name, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_tuple(len, visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
pass!(
|
||||
deserialize_tuple_struct,
|
||||
name: &'static str,
|
||||
len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_tuple_struct(name, len, visitor)
|
||||
}
|
||||
visitor: V
|
||||
);
|
||||
|
||||
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_map(visitor)
|
||||
}
|
||||
pass!(deserialize_map, visitor: V);
|
||||
|
||||
fn deserialize_struct<V>(
|
||||
self,
|
||||
pass!(
|
||||
deserialize_struct,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_struct(name, fields, visitor)
|
||||
}
|
||||
visitor: V
|
||||
);
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
pass!(
|
||||
deserialize_enum,
|
||||
name: &'static str,
|
||||
variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_enum(name, variants, visitor)
|
||||
}
|
||||
fields: &'static [&'static str],
|
||||
visitor: V
|
||||
);
|
||||
|
||||
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_identifier(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
kv_value!(self).deserialize_ignored_any(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait implemented by command arguments to derive a value from a [`InvokeMessage`].
|
||||
/// [`tauri::Window`], [`tauri::State`] and types that implements [`Deserialize`] automatically implements this trait.
|
||||
pub trait FromCommand<'de, P: Params>: Sized {
|
||||
/// Derives an instance of `Self` from the [`InvokeMessage`].
|
||||
/// If the derivation fails, the corresponding message will be rejected using [`InvokeMessage#reject`].
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `command`: the command value passed to invoke, e.g. `initialize` on `invoke('initialize', {})`.
|
||||
/// - `key`: The name of the variable in the command handler, e.g. `value` on `#[command] fn handler(value: u64)`
|
||||
/// - `message`: The [`InvokeMessage`] instance.
|
||||
fn from_command(
|
||||
command: &'de str,
|
||||
key: &'de str,
|
||||
message: &'de InvokeMessage<P>,
|
||||
) -> ::core::result::Result<Self, serde_json::Error>;
|
||||
}
|
||||
|
||||
impl<'de, D: serde::Deserialize<'de>, P: Params> FromCommand<'de, P> for D {
|
||||
fn from_command(
|
||||
command: &'de str,
|
||||
key: &'de str,
|
||||
message: &'de InvokeMessage<P>,
|
||||
) -> ::core::result::Result<Self, serde_json::Error> {
|
||||
D::deserialize(KeyedValue {
|
||||
command,
|
||||
key,
|
||||
value: &message.payload,
|
||||
})
|
||||
}
|
||||
pass!(deserialize_identifier, visitor: V);
|
||||
pass!(deserialize_ignored_any, visitor: V);
|
||||
}
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
use crate::{
|
||||
api::{config::Config, PackageInfo},
|
||||
hooks::{InvokeMessage, InvokeResolver},
|
||||
Params, Window,
|
||||
hooks::{InvokeError, InvokeMessage, InvokeResolver},
|
||||
Invoke, Params, Window,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
@ -66,67 +66,46 @@ impl Module {
|
||||
cmd
|
||||
.run(package_info)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
}),
|
||||
Self::Process(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run()
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
}),
|
||||
Self::Fs(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run()
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
Self::Process(cmd) => resolver
|
||||
.respond_async(async move { cmd.run().and_then(|r| r.json).map_err(InvokeError::from) }),
|
||||
Self::Fs(cmd) => resolver
|
||||
.respond_async(async move { cmd.run().and_then(|r| r.json).map_err(InvokeError::from) }),
|
||||
Self::Window(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(window)
|
||||
.await
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
Self::Shell(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(window)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
Self::Event(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(window)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
Self::Internal(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(window)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
}),
|
||||
Self::Dialog(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run()
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
Self::Dialog(cmd) => resolver
|
||||
.respond_async(async move { cmd.run().and_then(|r| r.json).map_err(InvokeError::from) }),
|
||||
Self::Cli(cmd) => {
|
||||
if let Some(cli_config) = config.tauri.cli.clone() {
|
||||
resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(&cli_config)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -136,8 +115,7 @@ impl Module {
|
||||
cmd
|
||||
.run(identifier)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
})
|
||||
}
|
||||
Self::Http(cmd) => resolver.respond_async(async move {
|
||||
@ -145,32 +123,35 @@ impl Module {
|
||||
.run()
|
||||
.await
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
Self::GlobalShortcut(cmd) => resolver.respond_async(async move {
|
||||
cmd
|
||||
.run(window)
|
||||
.and_then(|r| r.json)
|
||||
.map_err(|e| e.to_string())
|
||||
.into()
|
||||
.map_err(InvokeError::from)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle<M: Params>(
|
||||
pub(crate) fn handle<P: Params>(
|
||||
module: String,
|
||||
message: InvokeMessage<M>,
|
||||
resolver: InvokeResolver<M>,
|
||||
invoke: Invoke<P>,
|
||||
config: &Config,
|
||||
package_info: &PackageInfo,
|
||||
) {
|
||||
let mut payload = message.payload;
|
||||
let Invoke { message, resolver } = invoke;
|
||||
let InvokeMessage {
|
||||
mut payload,
|
||||
window,
|
||||
..
|
||||
} = message;
|
||||
|
||||
if let JsonValue::Object(ref mut obj) = payload {
|
||||
obj.insert("module".to_string(), JsonValue::String(module));
|
||||
}
|
||||
let window = message.window;
|
||||
|
||||
match serde_json::from_value::<Module>(payload) {
|
||||
Ok(module) => module.run(window, resolver, config, package_info.clone()),
|
||||
Err(e) => resolver.reject(e.to_string()),
|
||||
|
@ -27,8 +27,9 @@ pub enum Buffer {
|
||||
Raw(Vec<u8>),
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn default_env() -> Option<HashMap<String, String>> {
|
||||
Some(Default::default())
|
||||
Some(HashMap::default())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
@ -12,13 +12,13 @@ use serde_json::Value as JsonValue;
|
||||
use std::{future::Future, sync::Arc};
|
||||
|
||||
/// A closure that is run when the Tauri application is setting up.
|
||||
pub type SetupHook<M> = Box<dyn Fn(&mut App<M>) -> Result<(), Box<dyn std::error::Error>> + Send>;
|
||||
pub type SetupHook<P> = Box<dyn Fn(&mut App<P>) -> Result<(), Box<dyn std::error::Error>> + Send>;
|
||||
|
||||
/// A closure that is run everytime Tauri receives a message it doesn't explicitly handle.
|
||||
pub type InvokeHandler<M> = dyn Fn(InvokeMessage<M>, InvokeResolver<M>) + Send + Sync + 'static;
|
||||
pub type InvokeHandler<P> = dyn Fn(Invoke<P>) + Send + Sync + 'static;
|
||||
|
||||
/// A closure that is run once every time a window is created and loaded.
|
||||
pub type OnPageLoad<M> = dyn Fn(Window<M>, PageLoadPayload) + Send + Sync + 'static;
|
||||
pub type OnPageLoad<P> = dyn Fn(Window<P>, PageLoadPayload) + Send + Sync + 'static;
|
||||
|
||||
/// The payload for the [`OnPageLoad`] hook.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@ -33,33 +33,67 @@ impl PageLoadPayload {
|
||||
}
|
||||
}
|
||||
|
||||
/// The message and resolver given to a custom command.
|
||||
pub struct Invoke<P: Params> {
|
||||
/// The message passed.
|
||||
pub message: InvokeMessage<P>,
|
||||
|
||||
/// The resolver of the message.
|
||||
pub resolver: InvokeResolver<P>,
|
||||
}
|
||||
|
||||
/// Error response from an [`InvokeMessage`].
|
||||
#[derive(Debug)]
|
||||
pub struct InvokeError(JsonValue);
|
||||
|
||||
impl InvokeError {
|
||||
/// Create an [`InvokeError`] as a string of the [`serde_json::Error`] message.
|
||||
pub fn from_serde_json(error: serde_json::Error) -> Self {
|
||||
Self(JsonValue::String(error.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize> From<T> for InvokeError {
|
||||
fn from(value: T) -> Self {
|
||||
serde_json::to_value(value)
|
||||
.map(Self)
|
||||
.unwrap_or_else(Self::from_serde_json)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Error> for InvokeError {
|
||||
fn from(error: crate::Error) -> Self {
|
||||
Self(JsonValue::String(error.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Response from a [`InvokeMessage`] passed to the [`InvokeResolver`].
|
||||
#[derive(Debug)]
|
||||
pub enum InvokeResponse {
|
||||
/// Resolve the promise.
|
||||
Ok(JsonValue),
|
||||
/// Reject the promise.
|
||||
Err(JsonValue),
|
||||
Err(InvokeError),
|
||||
}
|
||||
|
||||
impl<T: Serialize, E: Serialize> From<Result<T, E>> for InvokeResponse {
|
||||
fn from(result: Result<T, E>) -> Self {
|
||||
match result {
|
||||
Result::Ok(t) => match serde_json::to_value(t) {
|
||||
Ok(v) => Self::Ok(v),
|
||||
Err(e) => Self::Err(JsonValue::String(e.to_string())),
|
||||
},
|
||||
Result::Err(e) => Self::error(e),
|
||||
impl InvokeResponse {
|
||||
/// Turn a [`InvokeResponse`] back into a serializable result.
|
||||
pub fn into_result(self) -> Result<JsonValue, JsonValue> {
|
||||
match self {
|
||||
Self::Ok(v) => Ok(v),
|
||||
Self::Err(e) => Err(e.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InvokeResponse {
|
||||
#[doc(hidden)]
|
||||
pub fn error<T: Serialize>(value: T) -> Self {
|
||||
match serde_json::to_value(value) {
|
||||
Ok(v) => Self::Err(v),
|
||||
Err(e) => Self::Err(JsonValue::String(e.to_string())),
|
||||
impl<T: Serialize> From<Result<T, InvokeError>> for InvokeResponse {
|
||||
fn from(result: Result<T, InvokeError>) -> Self {
|
||||
match result {
|
||||
Ok(ok) => match serde_json::to_value(ok) {
|
||||
Ok(value) => Self::Ok(value),
|
||||
Err(err) => Self::Err(InvokeError::from_serde_json(err)),
|
||||
},
|
||||
Err(err) => Self::Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,19 +106,8 @@ pub struct InvokeResolver<M: Params> {
|
||||
pub(crate) error: String,
|
||||
}
|
||||
|
||||
/*impl<P: Params> Clone for InvokeResolver<P> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
window: self.window.clone(),
|
||||
main_thread: self.main_thread,
|
||||
callback: self.callback.clone(),
|
||||
error: self.error.clone(),
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
impl<M: Params> InvokeResolver<M> {
|
||||
pub(crate) fn new(window: Window<M>, main_thread: bool, callback: String, error: String) -> Self {
|
||||
impl<P: Params> InvokeResolver<P> {
|
||||
pub(crate) fn new(window: Window<P>, main_thread: bool, callback: String, error: String) -> Self {
|
||||
Self {
|
||||
window,
|
||||
main_thread,
|
||||
@ -94,7 +117,11 @@ impl<M: Params> InvokeResolver<M> {
|
||||
}
|
||||
|
||||
/// Reply to the invoke promise with an async task.
|
||||
pub fn respond_async<F: Future<Output = InvokeResponse> + Send + 'static>(self, task: F) {
|
||||
pub fn respond_async<T, F>(self, task: F)
|
||||
where
|
||||
T: Serialize,
|
||||
F: Future<Output = Result<T, InvokeError>> + Send + 'static,
|
||||
{
|
||||
if self.main_thread {
|
||||
crate::async_runtime::block_on(async move {
|
||||
Self::return_task(self.window, task, self.callback, self.error).await;
|
||||
@ -107,25 +134,24 @@ impl<M: Params> InvokeResolver<M> {
|
||||
}
|
||||
|
||||
/// Reply to the invoke promise running the given closure.
|
||||
pub fn respond_closure<F: FnOnce() -> InvokeResponse>(self, f: F) {
|
||||
pub fn respond_closure<T, F>(self, f: F)
|
||||
where
|
||||
T: Serialize,
|
||||
F: FnOnce() -> Result<T, InvokeError>,
|
||||
{
|
||||
Self::return_closure(self.window, f, self.callback, self.error)
|
||||
}
|
||||
|
||||
/// Resolve the invoke promise with a value.
|
||||
pub fn resolve<S: Serialize>(self, value: S) {
|
||||
Self::return_result(
|
||||
self.window,
|
||||
Result::<S, ()>::Ok(value).into(),
|
||||
self.callback,
|
||||
self.error,
|
||||
)
|
||||
Self::return_result(self.window, Ok(value), self.callback, self.error)
|
||||
}
|
||||
|
||||
/// Reject the invoke promise with a value.
|
||||
pub fn reject<S: Serialize>(self, value: S) {
|
||||
Self::return_result(
|
||||
self.window,
|
||||
Result::<(), S>::Err(value).into(),
|
||||
Result::<(), _>::Err(value.into()),
|
||||
self.callback,
|
||||
self.error,
|
||||
)
|
||||
@ -136,18 +162,21 @@ impl<M: Params> InvokeResolver<M> {
|
||||
///
|
||||
/// If the Result `is_ok()`, the callback will be the `success_callback` function name and the argument will be the Ok value.
|
||||
/// If the Result `is_err()`, the callback will be the `error_callback` function name and the argument will be the Err value.
|
||||
pub async fn return_task<F: std::future::Future<Output = InvokeResponse> + Send + 'static>(
|
||||
window: Window<M>,
|
||||
pub async fn return_task<T, F>(
|
||||
window: Window<P>,
|
||||
task: F,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
) {
|
||||
) where
|
||||
T: Serialize,
|
||||
F: Future<Output = Result<T, InvokeError>> + Send + 'static,
|
||||
{
|
||||
let result = task.await;
|
||||
Self::return_closure(window, || result, success_callback, error_callback)
|
||||
}
|
||||
|
||||
pub(crate) fn return_closure<F: FnOnce() -> InvokeResponse>(
|
||||
window: Window<M>,
|
||||
pub(crate) fn return_closure<T: Serialize, F: FnOnce() -> Result<T, InvokeError>>(
|
||||
window: Window<P>,
|
||||
f: F,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
@ -155,17 +184,14 @@ impl<M: Params> InvokeResolver<M> {
|
||||
Self::return_result(window, f(), success_callback, error_callback)
|
||||
}
|
||||
|
||||
pub(crate) fn return_result(
|
||||
window: Window<M>,
|
||||
response: InvokeResponse,
|
||||
pub(crate) fn return_result<T: Serialize>(
|
||||
window: Window<P>,
|
||||
response: Result<T, InvokeError>,
|
||||
success_callback: String,
|
||||
error_callback: String,
|
||||
) {
|
||||
let callback_string = match format_callback_result(
|
||||
match response {
|
||||
InvokeResponse::Ok(t) => std::result::Result::Ok(t),
|
||||
InvokeResponse::Err(e) => std::result::Result::Err(e),
|
||||
},
|
||||
InvokeResponse::from(response).into_result(),
|
||||
success_callback,
|
||||
error_callback.clone(),
|
||||
) {
|
||||
@ -190,10 +216,10 @@ pub struct InvokeMessage<M: Params> {
|
||||
pub(crate) payload: JsonValue,
|
||||
}
|
||||
|
||||
impl<M: Params> InvokeMessage<M> {
|
||||
impl<P: Params> InvokeMessage<P> {
|
||||
/// Create an new [`InvokeMessage`] from a payload send to a window.
|
||||
pub(crate) fn new(
|
||||
window: Window<M>,
|
||||
window: Window<P>,
|
||||
state: Arc<StateManager>,
|
||||
command: String,
|
||||
payload: JsonValue,
|
||||
@ -207,12 +233,38 @@ impl<M: Params> InvokeMessage<M> {
|
||||
}
|
||||
|
||||
/// The invoke command.
|
||||
#[inline(always)]
|
||||
pub fn command(&self) -> &str {
|
||||
&self.command
|
||||
}
|
||||
|
||||
/// The window that received the invoke.
|
||||
pub fn window(&self) -> Window<M> {
|
||||
#[inline(always)]
|
||||
pub fn window(&self) -> Window<P> {
|
||||
self.window.clone()
|
||||
}
|
||||
|
||||
/// A reference to window that received the invoke.
|
||||
#[inline(always)]
|
||||
pub fn window_ref(&self) -> &Window<P> {
|
||||
&self.window
|
||||
}
|
||||
|
||||
/// A reference to the payload the invoke received.
|
||||
#[inline(always)]
|
||||
pub fn payload(&self) -> &JsonValue {
|
||||
&self.payload
|
||||
}
|
||||
|
||||
/// The state manager associated with the application
|
||||
#[inline(always)]
|
||||
pub fn state(&self) -> Arc<StateManager> {
|
||||
self.state.clone()
|
||||
}
|
||||
|
||||
/// A reference to the state manager associated with application.
|
||||
#[inline(always)]
|
||||
pub fn state_ref(&self) -> &StateManager {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ use std::{borrow::Borrow, collections::HashMap, path::PathBuf};
|
||||
pub use {
|
||||
self::api::config::WindowUrl,
|
||||
self::hooks::{
|
||||
InvokeHandler, InvokeMessage, InvokeResolver, InvokeResponse, OnPageLoad, PageLoadPayload,
|
||||
SetupHook,
|
||||
Invoke, InvokeError, InvokeHandler, InvokeMessage, InvokeResolver, InvokeResponse, OnPageLoad,
|
||||
PageLoadPayload, SetupHook,
|
||||
},
|
||||
self::runtime::app::{App, Builder},
|
||||
self::runtime::flavors::wry::Wry,
|
||||
|
@ -4,11 +4,7 @@
|
||||
|
||||
//! Extend Tauri functionality.
|
||||
|
||||
use crate::{
|
||||
api::config::PluginConfig,
|
||||
hooks::{InvokeMessage, InvokeResolver, PageLoadPayload},
|
||||
App, Params, Window,
|
||||
};
|
||||
use crate::{api::config::PluginConfig, App, Invoke, PageLoadPayload, Params, Window};
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -16,13 +12,13 @@ use std::collections::HashMap;
|
||||
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
/// The plugin interface.
|
||||
pub trait Plugin<M: Params>: Send {
|
||||
pub trait Plugin<P: Params>: Send {
|
||||
/// The plugin name. Used as key on the plugin config object.
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
/// Initialize the plugin.
|
||||
#[allow(unused_variables)]
|
||||
fn initialize(&mut self, app: &App<M>, config: JsonValue) -> Result<()> {
|
||||
fn initialize(&mut self, app: &App<P>, config: JsonValue) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -37,23 +33,23 @@ pub trait Plugin<M: Params>: Send {
|
||||
|
||||
/// Callback invoked when the webview is created.
|
||||
#[allow(unused_variables)]
|
||||
fn created(&mut self, window: Window<M>) {}
|
||||
fn created(&mut self, window: Window<P>) {}
|
||||
|
||||
/// Callback invoked when the webview performs a navigation.
|
||||
#[allow(unused_variables)]
|
||||
fn on_page_load(&mut self, window: Window<M>, payload: PageLoadPayload) {}
|
||||
fn on_page_load(&mut self, window: Window<P>, payload: PageLoadPayload) {}
|
||||
|
||||
/// Add invoke_handler API extension commands.
|
||||
#[allow(unused_variables)]
|
||||
fn extend_api(&mut self, message: InvokeMessage<M>, resolver: InvokeResolver<M>) {}
|
||||
fn extend_api(&mut self, invoke: Invoke<P>) {}
|
||||
}
|
||||
|
||||
/// Plugin collection type.
|
||||
pub(crate) struct PluginStore<M: Params> {
|
||||
store: HashMap<&'static str, Box<dyn Plugin<M>>>,
|
||||
pub(crate) struct PluginStore<P: Params> {
|
||||
store: HashMap<&'static str, Box<dyn Plugin<P>>>,
|
||||
}
|
||||
|
||||
impl<M: Params> Default for PluginStore<M> {
|
||||
impl<P: Params> Default for PluginStore<P> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
store: HashMap::new(),
|
||||
@ -61,16 +57,16 @@ impl<M: Params> Default for PluginStore<M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Params> PluginStore<M> {
|
||||
impl<P: Params> PluginStore<P> {
|
||||
/// Adds a plugin to the store.
|
||||
///
|
||||
/// Returns `true` if a plugin with the same name is already in the store.
|
||||
pub fn register<P: Plugin<M> + 'static>(&mut self, plugin: P) -> bool {
|
||||
pub fn register<Plug: Plugin<P> + 'static>(&mut self, plugin: Plug) -> bool {
|
||||
self.store.insert(plugin.name(), Box::new(plugin)).is_some()
|
||||
}
|
||||
|
||||
/// Initializes all plugins in the store.
|
||||
pub(crate) fn initialize(&mut self, app: &App<M>, config: &PluginConfig) -> crate::Result<()> {
|
||||
pub(crate) fn initialize(&mut self, app: &App<P>, config: &PluginConfig) -> crate::Result<()> {
|
||||
self.store.values_mut().try_for_each(|plugin| {
|
||||
plugin
|
||||
.initialize(
|
||||
@ -93,7 +89,7 @@ impl<M: Params> PluginStore<M> {
|
||||
}
|
||||
|
||||
/// Runs the created hook for all plugins in the store.
|
||||
pub(crate) fn created(&mut self, window: Window<M>) {
|
||||
pub(crate) fn created(&mut self, window: Window<P>) {
|
||||
self
|
||||
.store
|
||||
.values_mut()
|
||||
@ -101,27 +97,29 @@ impl<M: Params> PluginStore<M> {
|
||||
}
|
||||
|
||||
/// Runs the on_page_load hook for all plugins in the store.
|
||||
pub(crate) fn on_page_load(&mut self, window: Window<M>, payload: PageLoadPayload) {
|
||||
pub(crate) fn on_page_load(&mut self, window: Window<P>, payload: PageLoadPayload) {
|
||||
self
|
||||
.store
|
||||
.values_mut()
|
||||
.for_each(|plugin| plugin.on_page_load(window.clone(), payload.clone()))
|
||||
}
|
||||
|
||||
pub(crate) fn extend_api(&mut self, mut message: InvokeMessage<M>, resolver: InvokeResolver<M>) {
|
||||
let command = message.command.replace("plugin:", "");
|
||||
pub(crate) fn extend_api(&mut self, mut invoke: Invoke<P>) {
|
||||
let command = invoke.message.command.replace("plugin:", "");
|
||||
let mut tokens = command.split('|');
|
||||
// safe to unwrap: split always has a least one item
|
||||
let target = tokens.next().unwrap();
|
||||
|
||||
if let Some(plugin) = self.store.get_mut(target) {
|
||||
message.command = tokens
|
||||
invoke.message.command = tokens
|
||||
.next()
|
||||
.map(|c| c.to_string())
|
||||
.unwrap_or_else(String::new);
|
||||
plugin.extend_api(message, resolver);
|
||||
plugin.extend_api(invoke);
|
||||
} else {
|
||||
resolver.reject(format!("plugin {} not found", target));
|
||||
invoke
|
||||
.resolver
|
||||
.reject(format!("plugin {} not found", target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use crate::{
|
||||
api::{assets::Assets, config::WindowUrl},
|
||||
hooks::{InvokeHandler, InvokeMessage, InvokeResolver, OnPageLoad, PageLoadPayload, SetupHook},
|
||||
hooks::{InvokeHandler, OnPageLoad, PageLoadPayload, SetupHook},
|
||||
plugin::{Plugin, PluginStore},
|
||||
runtime::{
|
||||
flavors::wry::Wry,
|
||||
@ -15,7 +15,7 @@ use crate::{
|
||||
Dispatch, Runtime,
|
||||
},
|
||||
sealed::{ManagerBase, RuntimeOrDispatch},
|
||||
Context, Manager, Params, StateManager, Window,
|
||||
Context, Invoke, Manager, Params, StateManager, Window,
|
||||
};
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
@ -142,7 +142,7 @@ where
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
setup: Box::new(|_| Ok(())),
|
||||
invoke_handler: Box::new(|_, _| ()),
|
||||
invoke_handler: Box::new(|_| ()),
|
||||
on_page_load: Box::new(|_, _| ()),
|
||||
pending_windows: Default::default(),
|
||||
plugins: PluginStore::default(),
|
||||
@ -154,8 +154,7 @@ where
|
||||
/// Defines the JS message handler callback.
|
||||
pub fn invoke_handler<F>(mut self, invoke_handler: F) -> Self
|
||||
where
|
||||
F:
|
||||
Fn(InvokeMessage<Args<E, L, A, R>>, InvokeResolver<Args<E, L, A, R>>) + Send + Sync + 'static,
|
||||
F: Fn(Invoke<Args<E, L, A, R>>) + Send + Sync + 'static,
|
||||
{
|
||||
self.invoke_handler = Box::new(invoke_handler);
|
||||
self
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
PackageInfo,
|
||||
},
|
||||
event::{Event, EventHandler, Listeners},
|
||||
hooks::{InvokeHandler, InvokeMessage, InvokeResolver, OnPageLoad, PageLoadPayload},
|
||||
hooks::{InvokeHandler, OnPageLoad, PageLoadPayload},
|
||||
plugin::PluginStore,
|
||||
runtime::{
|
||||
tag::{tags_to_javascript_array, Tag, TagRef, ToJsString},
|
||||
@ -22,7 +22,7 @@ use crate::{
|
||||
Icon, Runtime,
|
||||
},
|
||||
sealed::ParamsBase,
|
||||
App, Context, Params, StateManager, Window,
|
||||
App, Context, Invoke, Params, StateManager, Window,
|
||||
};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
@ -401,7 +401,7 @@ mod test {
|
||||
let manager: WindowManager<Args<String, String, _, Wry>> = WindowManager::with_handlers(
|
||||
context,
|
||||
PluginStore::default(),
|
||||
Box::new(|_, _| ()),
|
||||
Box::new(|_| ()),
|
||||
Box::new(|_, _| ()),
|
||||
Default::default(),
|
||||
StateManager::new(),
|
||||
@ -416,8 +416,8 @@ mod test {
|
||||
}
|
||||
|
||||
impl<P: Params> WindowManager<P> {
|
||||
pub fn run_invoke_handler(&self, message: InvokeMessage<P>, resolver: InvokeResolver<P>) {
|
||||
(self.inner.invoke_handler)(message, resolver);
|
||||
pub fn run_invoke_handler(&self, invoke: Invoke<P>) {
|
||||
(self.inner.invoke_handler)(invoke);
|
||||
}
|
||||
|
||||
pub fn run_on_page_load(&self, window: Window<P>, payload: PageLoadPayload) {
|
||||
@ -430,13 +430,13 @@ impl<P: Params> WindowManager<P> {
|
||||
.on_page_load(window, payload);
|
||||
}
|
||||
|
||||
pub fn extend_api(&self, message: InvokeMessage<P>, resolver: InvokeResolver<P>) {
|
||||
pub fn extend_api(&self, invoke: Invoke<P>) {
|
||||
self
|
||||
.inner
|
||||
.plugins
|
||||
.lock()
|
||||
.expect("poisoned plugin store")
|
||||
.extend_api(message, resolver);
|
||||
.extend_api(invoke);
|
||||
}
|
||||
|
||||
pub fn initialize_plugins(&self, app: &App<P>) -> crate::Result<()> {
|
||||
|
@ -114,8 +114,9 @@ impl<M: Params> PartialEq for DetachedWindow<M> {
|
||||
/// We want to export the runtime related window at the crate root, but not look like a re-export.
|
||||
pub(crate) mod export {
|
||||
use super::*;
|
||||
use crate::command::FromCommand;
|
||||
use crate::command::{CommandArg, CommandItem};
|
||||
use crate::runtime::{manager::WindowManager, tag::TagRef};
|
||||
use crate::{Invoke, InvokeError};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// A webview window managed by Tauri.
|
||||
@ -167,13 +168,10 @@ pub(crate) mod export {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, P: Params> FromCommand<'de, P> for Window<P> {
|
||||
fn from_command(
|
||||
_: &'de str,
|
||||
_: &'de str,
|
||||
message: &'de InvokeMessage<P>,
|
||||
) -> Result<Self, serde_json::Error> {
|
||||
Ok(message.window())
|
||||
impl<'de, P: Params> CommandArg<'de, P> for Window<P> {
|
||||
/// Grabs the [`Window`] from the [`CommandItem`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.window())
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,19 +203,14 @@ pub(crate) mod export {
|
||||
);
|
||||
let resolver =
|
||||
InvokeResolver::new(self, payload.main_thread, payload.callback, payload.error);
|
||||
let invoke = Invoke { message, resolver };
|
||||
if let Some(module) = &payload.tauri_module {
|
||||
let module = module.to_string();
|
||||
crate::endpoints::handle(
|
||||
module,
|
||||
message,
|
||||
resolver,
|
||||
manager.config(),
|
||||
manager.package_info(),
|
||||
);
|
||||
crate::endpoints::handle(module, invoke, manager.config(), manager.package_info());
|
||||
} else if command.starts_with("plugin:") {
|
||||
manager.extend_api(message, resolver);
|
||||
manager.extend_api(invoke);
|
||||
} else {
|
||||
manager.run_invoke_handler(message, resolver);
|
||||
manager.run_invoke_handler(invoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::command::FromCommand;
|
||||
use crate::{InvokeMessage, Params};
|
||||
use crate::command::{CommandArg, CommandItem};
|
||||
use crate::{InvokeError, Params};
|
||||
use state::Container;
|
||||
|
||||
/// A guard for a state value.
|
||||
@ -34,13 +34,10 @@ impl<T: Send + Sync + 'static> Clone for State<'_, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, 'de: 'r, T: Send + Sync + 'static, P: Params> FromCommand<'de, P> for State<'r, T> {
|
||||
fn from_command(
|
||||
_: &'de str,
|
||||
_: &'de str,
|
||||
message: &'de InvokeMessage<P>,
|
||||
) -> Result<Self, serde_json::Error> {
|
||||
Ok(message.state.get())
|
||||
impl<'r, 'de: 'r, T: Send + Sync + 'static, P: Params> CommandArg<'de, P> for State<'r, T> {
|
||||
/// Grabs the [`State`] from the [`CommandItem`]. This will never fail.
|
||||
fn from_command(command: CommandItem<'de, P>) -> Result<Self, InvokeError> {
|
||||
Ok(command.message.state_ref().get())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ type Result<T> = std::result::Result<T, ()>;
|
||||
#[tauri::command]
|
||||
fn simple_command_with_result(argument: String) -> Result<String> {
|
||||
println!("{}", argument);
|
||||
Ok(argument)
|
||||
(!argument.is_empty()).then(|| argument).ok_or(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -51,7 +51,7 @@ fn stateful_command_with_result(
|
||||
state: tauri::State<'_, MyState>,
|
||||
) -> Result<String> {
|
||||
println!("{:?} {:?}", argument, state.inner());
|
||||
Ok(argument.unwrap_or_else(|| "".to_string()))
|
||||
argument.ok_or(())
|
||||
}
|
||||
|
||||
// Async commands
|
||||
|
Loading…
Reference in New Issue
Block a user