Skip to content

Commit 93c8a77

Browse files
refactor: enhance event system rust apis (#7996)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent 198abe3 commit 93c8a77

File tree

9 files changed

+521
-347
lines changed

9 files changed

+521
-347
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'tauri': 'major:breaking'
3+
---
4+
5+
The event system APIS on Rust is recieving a few changes for consistency and quality of life improvements:
6+
7+
- Renamed `Manager::emit_all` to just `Manager::emit` and will now both trigger the events on JS side as well as Rust.
8+
- Removed `Manager::trigger_global`, use `Manager::emit`
9+
- Added `Manager::emit_filter`.
10+
- Removed `Window::emit`, and moved the implementation to `Manager::emit`.
11+
- Removed `Window::emit_and_trigger` and `Window::trigger`, use `Window::emit` instead.
12+
- Changed `Window::emit_to` to only trigger the target window listeners so it won't be catched by `Manager::listen_global`

core/tauri/src/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ impl<R: Runtime> GlobalWindowEvent<R> {
246246
&self.event
247247
}
248248

249-
/// The window that the menu belongs to.
249+
/// The window that the event belongs to.
250250
pub fn window(&self) -> &Window<R> {
251251
&self.window
252252
}

core/tauri/src/event/listener.rs

Lines changed: 75 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// SPDX-License-Identifier: Apache-2.0
33
// SPDX-License-Identifier: MIT
44

5-
use super::{Event, EventId};
5+
use crate::{Runtime, Window};
6+
7+
use super::{EmitArgs, Event, EventId};
68

79
use std::{
810
boxed::Box,
@@ -15,33 +17,33 @@ use std::{
1517
};
1618

1719
/// What to do with the pending handler when resolving it?
18-
enum Pending {
20+
enum Pending<R: Runtime> {
1921
Unlisten(EventId),
20-
Listen(EventId, String, Handler),
21-
Trigger(String, Option<String>, Option<String>),
22+
Listen(EventId, String, Handler<R>),
23+
Emit(EmitArgs),
2224
}
2325

2426
/// Stored in [`Listeners`] to be called upon when the event that stored it is triggered.
25-
struct Handler {
26-
window: Option<String>,
27+
struct Handler<R: Runtime> {
28+
window: Option<Window<R>>,
2729
callback: Box<dyn Fn(Event) + Send>,
2830
}
2931

3032
/// Holds event handlers and pending event handlers, along with the salts associating them.
31-
struct InnerListeners {
32-
handlers: Mutex<HashMap<String, HashMap<EventId, Handler>>>,
33-
pending: Mutex<Vec<Pending>>,
33+
struct InnerListeners<R: Runtime> {
34+
handlers: Mutex<HashMap<String, HashMap<EventId, Handler<R>>>>,
35+
pending: Mutex<Vec<Pending<R>>>,
3436
function_name: &'static str,
3537
listeners_object_name: &'static str,
3638
next_event_id: Arc<AtomicU32>,
3739
}
3840

3941
/// A self-contained event manager.
40-
pub struct Listeners {
41-
inner: Arc<InnerListeners>,
42+
pub struct Listeners<R: Runtime> {
43+
inner: Arc<InnerListeners<R>>,
4244
}
4345

44-
impl Default for Listeners {
46+
impl<R: Runtime> Default for Listeners<R> {
4547
fn default() -> Self {
4648
Self {
4749
inner: Arc::new(InnerListeners {
@@ -55,15 +57,15 @@ impl Default for Listeners {
5557
}
5658
}
5759

58-
impl Clone for Listeners {
60+
impl<R: Runtime> Clone for Listeners<R> {
5961
fn clone(&self) -> Self {
6062
Self {
6163
inner: self.inner.clone(),
6264
}
6365
}
6466
}
6567

66-
impl Listeners {
68+
impl<R: Runtime> Listeners<R> {
6769
pub(crate) fn next_event_id(&self) -> EventId {
6870
self.inner.next_event_id.fetch_add(1, Ordering::Relaxed)
6971
}
@@ -79,7 +81,7 @@ impl Listeners {
7981
}
8082

8183
/// Insert a pending event action to the queue.
82-
fn insert_pending(&self, action: Pending) {
84+
fn insert_pending(&self, action: Pending<R>) {
8385
self
8486
.inner
8587
.pending
@@ -89,7 +91,7 @@ impl Listeners {
8991
}
9092

9193
/// Finish all pending event actions.
92-
fn flush_pending(&self) {
94+
fn flush_pending(&self) -> crate::Result<()> {
9395
let pending = {
9496
let mut lock = self
9597
.inner
@@ -102,13 +104,17 @@ impl Listeners {
102104
for action in pending {
103105
match action {
104106
Pending::Unlisten(id) => self.unlisten(id),
105-
Pending::Listen(id, event, handler) => self.listen_(id, event, handler),
106-
Pending::Trigger(ref event, window, payload) => self.trigger(event, window, payload),
107+
Pending::Listen(id, event, handler) => self.listen_with_id(id, event, handler),
108+
Pending::Emit(args) => {
109+
self.emit(&args)?;
110+
}
107111
}
108112
}
113+
114+
Ok(())
109115
}
110116

111-
fn listen_(&self, id: EventId, event: String, handler: Handler) {
117+
fn listen_with_id(&self, id: EventId, event: String, handler: Handler<R>) {
112118
match self.inner.handlers.try_lock() {
113119
Err(_) => self.insert_pending(Pending::Listen(id, event, handler)),
114120
Ok(mut lock) => {
@@ -117,11 +123,11 @@ impl Listeners {
117123
}
118124
}
119125

120-
/// Adds an event listener for JS events.
126+
/// Adds an event listener.
121127
pub(crate) fn listen<F: Fn(Event) + Send + 'static>(
122128
&self,
123129
event: String,
124-
window: Option<String>,
130+
window: Option<Window<R>>,
125131
handler: F,
126132
) -> EventId {
127133
let id = self.next_event_id();
@@ -130,16 +136,16 @@ impl Listeners {
130136
callback: Box::new(handler),
131137
};
132138

133-
self.listen_(id, event, handler);
139+
self.listen_with_id(id, event, handler);
134140

135141
id
136142
}
137143

138-
/// Listen to a JS event and immediately unlisten.
144+
/// Listen to an event and immediately unlisten.
139145
pub(crate) fn once<F: FnOnce(Event) + Send + 'static>(
140146
&self,
141147
event: String,
142-
window: Option<String>,
148+
window: Option<Window<R>>,
143149
handler: F,
144150
) {
145151
let self_ = self.clone();
@@ -164,19 +170,42 @@ impl Listeners {
164170
}
165171
}
166172

167-
/// Triggers the given global event with its payload.
168-
pub(crate) fn trigger(&self, event: &str, window: Option<String>, payload: Option<String>) {
173+
/// Emits the given event with its payload based on a filter.
174+
pub(crate) fn emit_filter<F>(&self, emit_args: &EmitArgs, filter: Option<F>) -> crate::Result<()>
175+
where
176+
F: Fn(&Window<R>) -> bool,
177+
{
169178
let mut maybe_pending = false;
170179
match self.inner.handlers.try_lock() {
171-
Err(_) => self.insert_pending(Pending::Trigger(event.to_owned(), window, payload)),
180+
Err(_) => self.insert_pending(Pending::Emit(emit_args.clone())),
172181
Ok(lock) => {
173-
if let Some(handlers) = lock.get(event) {
174-
for (&id, handler) in handlers {
175-
if handler.window.is_none() || window == handler.window {
182+
if let Some(handlers) = lock.get(&emit_args.event_name) {
183+
let handlers = if let Some(filter) = filter {
184+
handlers
185+
.iter()
186+
.filter(|h| {
187+
h.1
188+
.window
189+
.as_ref()
190+
.map(|w| {
191+
// clippy sees this as redundant closure but
192+
// fixing it will result in a compiler error
193+
#[allow(clippy::redundant_closure)]
194+
filter(w)
195+
})
196+
.unwrap_or(false)
197+
})
198+
.collect::<Vec<_>>()
199+
} else {
200+
handlers.iter().collect::<Vec<_>>()
201+
};
202+
203+
if !handlers.is_empty() {
204+
for (&id, handler) in handlers {
176205
maybe_pending = true;
177206
(handler.callback)(self::Event {
178207
id,
179-
data: payload.clone(),
208+
data: emit_args.payload.clone(),
180209
})
181210
}
182211
}
@@ -185,14 +214,22 @@ impl Listeners {
185214
}
186215

187216
if maybe_pending {
188-
self.flush_pending();
217+
self.flush_pending()?;
189218
}
219+
220+
Ok(())
221+
}
222+
223+
/// Emits the given event with its payload.
224+
pub(crate) fn emit(&self, emit_args: &EmitArgs) -> crate::Result<()> {
225+
self.emit_filter(emit_args, None::<&dyn Fn(&Window<R>) -> bool>)
190226
}
191227
}
192228

193229
#[cfg(test)]
194230
mod test {
195231
use super::*;
232+
use crate::test::MockRuntime;
196233
use proptest::prelude::*;
197234

198235
// dummy event handler function
@@ -206,7 +243,7 @@ mod test {
206243
// check to see if listen() is properly passing keys into the LISTENERS map
207244
#[test]
208245
fn listeners_check_key(e in "[a-z]+") {
209-
let listeners: Listeners = Default::default();
246+
let listeners: Listeners<MockRuntime> = Default::default();
210247
// clone e as the key
211248
let key = e.clone();
212249
// pass e and an dummy func into listen
@@ -222,7 +259,7 @@ mod test {
222259
// check to see if listen inputs a handler function properly into the LISTENERS map.
223260
#[test]
224261
fn listeners_check_fn(e in "[a-z]+") {
225-
let listeners: Listeners = Default::default();
262+
let listeners: Listeners<MockRuntime> = Default::default();
226263
// clone e as the key
227264
let key = e.clone();
228265
// pass e and an dummy func into listen
@@ -248,11 +285,11 @@ mod test {
248285
// check to see if on_event properly grabs the stored function from listen.
249286
#[test]
250287
fn check_on_event(key in "[a-z]+", d in "[a-z]+") {
251-
let listeners: Listeners = Default::default();
252-
// call listen with e and the event_fn dummy func
288+
let listeners: Listeners<MockRuntime> = Default::default();
289+
// call listen with key and the event_fn dummy func
253290
listeners.listen(key.clone(), None, event_fn);
254-
// call on event with e and d.
255-
listeners.trigger(&key, None, Some(d));
291+
// call on event with key and d.
292+
listeners.emit(&EmitArgs { event_name: key.clone(), event: serde_json::to_string(&key).unwrap(), source_window_label: "null".into(), payload: serde_json::to_string(&d).unwrap() })?;
256293

257294
// lock the mutex
258295
let l = listeners.inner.handlers.lock().unwrap();

0 commit comments

Comments
 (0)