wallet_adapter/wallet_ser_der/standard_features/
events.rs1use std::{future::Future, pin::Pin};
2
3use async_channel::Receiver;
4use web_sys::wasm_bindgen::{prelude::Closure, JsValue};
5
6use crate::{
7 ConnectionInfoInner, Reflection, SemverVersion, StandardFunction, WalletAccount, WalletError,
8 WalletEvent, WalletEventSender, WalletResult,
9};
10
11#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct StandardEvents(StandardFunction);
15
16impl StandardEvents {
17 pub(crate) fn new(reflection: &Reflection, version: SemverVersion) -> WalletResult<Self> {
19 let get_standard_event_fn = reflection.get_function("on")?;
20
21 Ok(Self(StandardFunction {
22 version,
23 callback: get_standard_event_fn,
24 }))
25 }
26
27 pub(crate) async fn call_on_event(
28 &self,
29 connection_info: ConnectionInfoInner,
30 wallet_name: String,
31 sender: WalletEventSender,
32 stop_signal: Receiver<()>,
33 ) -> WalletResult<()> {
34 let sender2 = sender.clone();
35
36 let on_account_change = Closure::wrap(Box::new(move |value: JsValue| {
37 let wallet_name = wallet_name.clone();
38 web_sys::console::log_3(
39 &"CALLED ON EV for ".into(),
40 &wallet_name.clone().into(),
41 &value,
42 );
43
44 let connection_info_inner = connection_info.clone();
45 let sender_inner = sender2.clone();
46
47 wasm_bindgen_futures::spawn_local(async move {
48 let reflect_accounts =
49 send_wallet_event_error()(Reflection::new(value), sender_inner.clone())
50 .await
51 .unwrap(); let mut get_accounts = send_wallet_event_error()(
53 reflect_accounts.reflect_js_array("accounts"),
54 sender_inner.clone(),
55 )
56 .await
57 .unwrap()
58 .to_vec(); let processed_wallet_account = if !get_accounts.is_empty() {
61 let first_account = send_wallet_event_error()(
62 Reflection::new(get_accounts.remove(0)),
63 sender_inner.clone(),
64 )
65 .await
66 .unwrap(); let account_processing = send_wallet_event_error()(
69 WalletAccount::parse(first_account),
70 sender_inner.clone(),
71 )
72 .await
73 .unwrap(); web_sys::console::error_2(
75 &"PRE ACCOUNT PROCESSING".into(),
76 &format!("{account_processing:?}").into(),
77 );
78
79 Some(account_processing)
80 } else {
81 Option::None
82 };
83
84 connection_info_inner
85 .write()
86 .await
87 .emit_wallet_event(&wallet_name, processed_wallet_account, sender_inner.clone())
88 .await
89 });
90 }) as Box<dyn Fn(_)>);
91
92 let on_account_change_fn =
93 Reflection::new(on_account_change.into_js_value())?.into_function()?;
94
95 let on_event_fn = self.0.callback.clone();
96
97 wasm_bindgen_futures::spawn_local(async move {
98 while (stop_signal.recv().await).is_ok() {
99 let invoke_outcome = on_event_fn
100 .call2(
101 &JsValue::null(),
102 &"change".into(),
103 &on_account_change_fn.clone().into(),
104 )
105 .map_err(|error| {
106 let into_error: WalletError = error.into();
107
108 into_error
109 });
110
111 send_wallet_event_error()(invoke_outcome, sender.clone())
112 .await
113 .unwrap();
114 }
115 });
116
117 Ok(())
118 }
119}
120
121pub(crate) async fn send_wallet_event(wallet_event: WalletEvent, sender: WalletEventSender) {
122 if let Err(error) = sender.clone().send(wallet_event).await {
123 web_sys::console::log_2(
124 &"BACKGROUND TASK ERROR: [standard:events]on() > ".into(),
125 &format!("{error:?}").into(),
126 );
127 }
128}
129
130type SendWalletEventErrorOutput<T> = Pin<Box<dyn Future<Output = Result<T, ()>>>>;
131
132pub(crate) fn send_wallet_event_error<T>(
133) -> impl Fn(WalletResult<T>, WalletEventSender) -> SendWalletEventErrorOutput<T> + 'static
134where
135 T: core::fmt::Debug + 'static,
136{
137 move |outcome: WalletResult<T>, sender: WalletEventSender| {
138 Box::pin(async move {
139 match outcome {
140 Ok(value) => Ok(value),
141 Err(error) => {
142 web_sys::console::log_2(
143 &"BACKGROUND TASK ERROR: [standard:events]on() > ".into(),
144 &format!("{error:?}").into(),
145 );
146
147 if let Err(channel_error) = sender
148 .send(WalletEvent::BackgroundTaskError(error.clone()))
149 .await
150 {
151 web_sys::console::log_2(
152 &"Encountered error while sending a wallet event: ".into(),
153 &format!("{channel_error:?}").into(),
154 );
155 }
156
157 Err(())
158 }
159 }
160 })
161 }
162}