1use crate::error::Result;
2use crate::store::{Store, StoreId, StoreOptions, StoreState};
3use serde::Serialize;
4use tauri::{AppHandle, Emitter as _, EventTarget, Runtime, WebviewWindow, Window};
5
6pub const STORE_CONFIG_CHANGE_EVENT: &str = "tauri-store://config-change";
7pub const STORE_STATE_CHANGE_EVENT: &str = "tauri-store://state-change";
8pub const STORE_UNLOAD_EVENT: &str = "tauri-store://unload";
9
10#[derive(Clone, Debug, Serialize)]
11#[serde(rename_all = "camelCase")]
12pub(crate) struct StatePayload<'a> {
13 id: &'a StoreId,
14 state: &'a StoreState,
15}
16
17impl<'a, R: Runtime> From<&'a Store<R>> for StatePayload<'a> {
18 fn from(store: &'a Store<R>) -> Self {
19 Self { id: &store.id, state: store.state() }
20 }
21}
22
23#[derive(Clone, Debug, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub(crate) struct ConfigPayload<'a> {
26 id: &'a StoreId,
27 config: StoreOptions,
28}
29
30impl<'a, R: Runtime> From<&'a Store<R>> for ConfigPayload<'a> {
31 fn from(store: &'a Store<R>) -> Self {
32 Self { id: &store.id, config: store.into() }
33 }
34}
35
36pub(crate) fn emit<R, T, S>(app: &AppHandle<R>, event: &str, payload: &T, source: S) -> Result<()>
37where
38 R: Runtime,
39 T: Serialize + ?Sized,
40 S: Into<EventSource>,
41{
42 let source: EventSource = source.into();
43 if let Some(source) = source.0 {
44 emit_filter(app, event, payload, |it| it != source)
45 } else {
46 emit_all(app, event, payload)
47 }
48}
49
50fn emit_all<R, T>(app: &AppHandle<R>, event: &str, payload: &T) -> Result<()>
51where
52 R: Runtime,
53 T: Serialize + ?Sized,
54{
55 app.emit_filter(event, payload, |target| {
56 matches!(target, EventTarget::WebviewWindow { .. })
57 })?;
58
59 Ok(())
60}
61
62fn emit_filter<R, T, F>(app: &AppHandle<R>, event: &str, payload: &T, f: F) -> Result<()>
63where
64 R: Runtime,
65 T: Serialize + ?Sized,
66 F: Fn(&str) -> bool,
67{
68 #[rustfmt::skip]
69 app.emit_filter(event, payload, |target| {
70 matches!(target, EventTarget::WebviewWindow { label } if f(label))
71 })?;
72
73 Ok(())
74}
75
76pub struct EventSource(Option<String>);
78
79impl EventSource {
80 #[inline]
81 pub const fn is_backend(&self) -> bool {
82 self.0.is_none()
83 }
84}
85
86impl From<&str> for EventSource {
87 fn from(source: &str) -> Self {
88 Self(Some(String::from(source)))
89 }
90}
91
92impl From<Option<&str>> for EventSource {
93 fn from(source: Option<&str>) -> Self {
94 Self(source.map(String::from))
95 }
96}
97
98impl From<String> for EventSource {
99 fn from(source: String) -> Self {
100 Self(Some(source))
101 }
102}
103
104impl From<&String> for EventSource {
105 fn from(source: &String) -> Self {
106 Self(Some(source.to_owned()))
107 }
108}
109
110impl From<Option<String>> for EventSource {
111 fn from(source: Option<String>) -> Self {
112 Self(source)
113 }
114}
115
116impl From<&WebviewWindow> for EventSource {
117 fn from(window: &WebviewWindow) -> Self {
118 Self(Some(window.label().to_owned()))
119 }
120}
121
122impl From<&Window> for EventSource {
123 fn from(window: &Window) -> Self {
124 Self(Some(window.label().to_owned()))
125 }
126}