tauri_wasm/
event.rs

1use {
2    crate::{
3        error::Error,
4        ext,
5        invoke::{Options, ToStringValue},
6    },
7    js_sys::JsString,
8    serde::Serialize,
9    wasm_bindgen::prelude::*,
10    wasm_bindgen_futures::JsFuture,
11};
12
13#[rustfmt::skip]
14#[wasm_bindgen]
15extern "C" {
16    #[wasm_bindgen(thread_local_v2, static_string)]
17    static EMIT: JsString = "plugin:event|emit";
18
19     #[wasm_bindgen(thread_local_v2, static_string)]
20    static EMIT_TO: JsString = "plugin:event|emit_to";
21}
22
23/// Sends an [event] to the backend.
24///
25/// [event]: https://v2.tauri.app/develop/calling-rust/#event-system
26///
27/// # Example
28///
29/// Send an event with string payload.
30///
31#[cfg_attr(feature = "serde", doc = "```")]
32#[cfg_attr(not(feature = "serde"), doc = "```ignore")]
33/// # async fn e() -> Result<(), tauri_wasm::Error> {
34/// tauri_wasm::emit("file-selected", "/path/to/file").await?;
35/// # Ok(())
36/// # }
37/// ```
38///
39/// You can send any [serializable](Serialize) payload.
40///
41#[cfg_attr(feature = "serde", doc = "```")]
42#[cfg_attr(not(feature = "serde"), doc = "```ignore")]
43/// # async fn e() -> Result<(), tauri_wasm::Error> {
44/// use serde::Serialize;
45///
46/// #[derive(Serialize)]
47/// struct Message {
48///     key: &'static str,
49///     data: u32,
50/// }
51///
52/// let message = Message {
53///     key: "secret",
54///     data: 37,
55/// };
56///
57/// tauri_wasm::emit("file-selected", &message).await?;
58/// # Ok(())
59/// # }
60/// ```
61///
62/// To trigger an event to a listener registered by a specific target
63/// you can use the [`emit_to`] function.
64#[inline]
65pub async fn emit<E, P>(event: E, payload: &P) -> Result<(), Error>
66where
67    E: ToStringValue,
68    P: Serialize + ?Sized,
69{
70    let event = event.to_string_value();
71
72    let payload = serde_wasm_bindgen::to_value(&payload).map_err(|e| Error(JsValue::from(e)))?;
73
74    invoke_emit(None, event.as_ref(), &payload)
75        .await
76        .map_err(Error)?;
77
78    Ok(())
79}
80
81/// Sends an [event] to a listener registered by a specific target.
82///
83/// [event]: https://v2.tauri.app/develop/calling-rust/#event-system
84///
85/// # Example
86///
87/// Send an event with string payload to the target with "editor" label.
88///
89#[cfg_attr(feature = "serde", doc = "```")]
90#[cfg_attr(not(feature = "serde"), doc = "```ignore")]
91/// # async fn e() -> Result<(), tauri_wasm::Error> {
92/// use tauri_wasm::EventTarget;
93///
94/// let target = EventTarget::from("editor");
95/// tauri_wasm::emit_to(target, "file-selected", "/path/to/file").await?;
96/// # Ok(())
97/// # }
98/// ```
99#[inline]
100pub async fn emit_to<S, E, P>(target: EventTarget<S>, event: E, payload: &P) -> Result<(), Error>
101where
102    S: ToStringValue,
103    E: ToStringValue,
104    P: Serialize + ?Sized,
105{
106    let target = target.map(|s| s.to_string_value());
107    let target = target.as_ref().map(|s| s.as_ref());
108    let event = event.to_string_value();
109
110    let payload = serde_wasm_bindgen::to_value(&payload).map_err(|e| Error(JsValue::from(e)))?;
111
112    invoke_emit(Some(target), event.as_ref(), &payload)
113        .await
114        .map_err(Error)?;
115
116    Ok(())
117}
118
119#[inline]
120fn invoke_emit(
121    target: Option<EventTarget<&JsValue>>,
122    event: &JsValue,
123    payload: &JsValue,
124) -> JsFuture {
125    let cmd = if target.is_none() { &EMIT } else { &EMIT_TO };
126
127    let (kind, label) = match target {
128        None => (0, &JsValue::UNDEFINED),
129        Some(target) => match target {
130            EventTarget::Any => (1, &JsValue::UNDEFINED),
131            EventTarget::AnyLabel(s) => (2, s),
132            EventTarget::App => (3, &JsValue::UNDEFINED),
133            EventTarget::Window(s) => (4, s),
134            EventTarget::Webview(s) => (5, s),
135            EventTarget::WebviewWindow(s) => (6, s),
136        },
137    };
138
139    let cmd = cmd.with(|s| JsValue::from(s));
140    let args = ext::eargs(event, payload, kind, label);
141    JsFuture::from(ext::invoke(&cmd, &args, Options::empty()))
142}
143
144/// An argument of event target for the [`emit_to`] function.
145pub enum EventTarget<S> {
146    Any,
147    AnyLabel(S),
148    App,
149    Window(S),
150    Webview(S),
151    WebviewWindow(S),
152}
153
154impl<S> EventTarget<S> {
155    #[inline]
156    pub fn from_string(s: S) -> Self {
157        Self::AnyLabel(s)
158    }
159
160    #[inline]
161    pub fn as_ref(&self) -> EventTarget<&S> {
162        match self {
163            Self::Any => EventTarget::Any,
164            Self::AnyLabel(s) => EventTarget::AnyLabel(s),
165            Self::App => EventTarget::App,
166            Self::Window(s) => EventTarget::Window(s),
167            Self::Webview(s) => EventTarget::Webview(s),
168            Self::WebviewWindow(s) => EventTarget::WebviewWindow(s),
169        }
170    }
171
172    #[inline]
173    pub fn map<F, T>(self, f: F) -> EventTarget<T>
174    where
175        F: FnOnce(S) -> T,
176    {
177        match self {
178            Self::Any => EventTarget::Any,
179            Self::AnyLabel(s) => EventTarget::AnyLabel(f(s)),
180            Self::App => EventTarget::App,
181            Self::Window(s) => EventTarget::Window(f(s)),
182            Self::Webview(s) => EventTarget::Webview(f(s)),
183            Self::WebviewWindow(s) => EventTarget::WebviewWindow(f(s)),
184        }
185    }
186}
187
188impl From<&str> for EventTarget<JsString> {
189    #[inline]
190    fn from(s: &str) -> Self {
191        Self::from_string(JsString::from(s))
192    }
193}