breez_sdk_spark/
events.rs1use core::fmt;
2use std::{collections::HashMap, sync::RwLock};
3
4use serde::Serialize;
5use uuid::Uuid;
6
7use crate::{DepositInfo, Payment};
8
9#[allow(clippy::large_enum_variant)]
11#[derive(Debug, Clone, Serialize)]
12#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
13pub enum SdkEvent {
14 Synced,
16 ClaimDepositsFailed {
18 unclaimed_deposits: Vec<DepositInfo>,
19 },
20 ClaimDepositsSucceeded {
21 claimed_deposits: Vec<DepositInfo>,
22 },
23 PaymentSucceeded {
24 payment: Payment,
25 },
26}
27
28impl fmt::Display for SdkEvent {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 SdkEvent::Synced => write!(f, "Synced"),
32 SdkEvent::ClaimDepositsFailed { unclaimed_deposits } => {
33 write!(f, "ClaimDepositsFailed: {unclaimed_deposits:?}")
34 }
35 SdkEvent::ClaimDepositsSucceeded { claimed_deposits } => {
36 write!(f, "ClaimDepositsSucceeded: {claimed_deposits:?}")
37 }
38 SdkEvent::PaymentSucceeded { payment } => {
39 write!(f, "PaymentSucceeded: {payment:?}")
40 }
41 }
42 }
43}
44
45#[cfg_attr(feature = "uniffi", uniffi::export(callback_interface))]
47pub trait EventListener: Send + Sync {
48 fn on_event(&self, event: SdkEvent);
50}
51
52pub struct EventEmitter {
54 listeners: RwLock<HashMap<String, Box<dyn EventListener>>>,
55}
56
57impl EventEmitter {
58 pub fn new() -> Self {
60 Self {
61 listeners: RwLock::new(HashMap::new()),
62 }
63 }
64
65 pub fn add_listener(&self, listener: Box<dyn EventListener>) -> String {
75 let id = Uuid::new_v4().to_string();
76 let mut listeners = self.listeners.write().unwrap();
77 listeners.insert(id.clone(), listener);
78 id
79 }
80
81 pub fn remove_listener(&self, id: &str) -> bool {
91 let mut listeners = self.listeners.write().unwrap();
92 listeners.remove(id).is_some()
93 }
94
95 pub fn emit(&self, event: &SdkEvent) {
97 let listeners = self.listeners.read().unwrap();
99
100 for listener in listeners.values() {
102 listener.on_event(event.clone());
103 }
104 }
105}
106
107impl Default for EventEmitter {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use std::sync::Arc;
117 use std::sync::atomic::{AtomicBool, Ordering};
118
119 use macros::test_all;
120
121 #[cfg(feature = "browser-tests")]
122 wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
123
124 struct TestListener {
125 received: Arc<AtomicBool>,
126 }
127
128 impl EventListener for TestListener {
129 fn on_event(&self, _event: SdkEvent) {
130 self.received.store(true, Ordering::Relaxed);
131 }
132 }
133
134 #[test_all]
135 fn test_event_emission() {
136 let emitter = EventEmitter::new();
137 let received = Arc::new(AtomicBool::new(false));
138
139 let listener = Box::new(TestListener {
141 received: received.clone(),
142 });
143
144 let _ = emitter.add_listener(listener);
145
146 let event = SdkEvent::Synced {};
147
148 emitter.emit(&event);
149
150 assert!(received.load(Ordering::Relaxed));
152 }
153
154 #[test_all]
155 fn test_remove_listener() {
156 let emitter = EventEmitter::new();
157
158 let received1 = Arc::new(AtomicBool::new(false));
160 let received2 = Arc::new(AtomicBool::new(false));
161
162 let listener1 = Box::new(TestListener {
164 received: received1.clone(),
165 });
166
167 let listener2 = Box::new(TestListener {
168 received: received2.clone(),
169 });
170
171 let id1 = emitter.add_listener(listener1);
172 let id2 = emitter.add_listener(listener2);
173
174 assert!(emitter.remove_listener(&id1));
176
177 let event = SdkEvent::Synced {};
179 emitter.emit(&event);
180
181 assert!(!received1.load(Ordering::Relaxed));
183
184 assert!(received2.load(Ordering::Relaxed));
186
187 assert!(emitter.remove_listener(&id2));
189
190 assert!(!emitter.remove_listener("non-existent-id"));
192 }
193}