chat_platform_wasm/
tab_lock.rs1#[cfg(target_arch = "wasm32")]
7use wasm_bindgen::prelude::*;
8#[cfg(target_arch = "wasm32")]
9use wasm_bindgen::closure::Closure;
10#[cfg(target_arch = "wasm32")]
11use web_sys::BroadcastChannel;
12
13pub struct TabLock {
15 #[cfg(target_arch = "wasm32")]
16 _channel: BroadcastChannel,
17 #[cfg(not(target_arch = "wasm32"))]
18 _nop: (),
19}
20
21impl TabLock {
22 #[cfg(target_arch = "wasm32")]
25 pub fn try_acquire(lock_name: &str) -> Option<Self> {
26 let channel = match BroadcastChannel::new(lock_name) {
27 Ok(c) => c,
28 Err(_) => return None,
29 };
30
31 let has_other = std::cell::Cell::new(false);
33 let has_other_ref = &has_other;
34
35 let on_message = Closure::wrap(Box::new(move |event: web_sys::MessageEvent| {
36 if let Some(data) = event.data().as_string()
37 && data == "pong"
38 {
39 has_other_ref.set(true);
40 }
41 }) as Box<dyn FnMut(_)>);
42
43 channel.set_onmessage(Some(on_message.as_ref().unchecked_ref()));
44
45 let _ = channel.post_message(&JsValue::from_str("ping"));
47
48 let start = js_sys::Date::now();
50 while js_sys::Date::now() - start < 100.0 && !has_other.get() {
51 }
53
54 channel.set_onmessage(None);
55 on_message.forget();
56
57 if has_other.get() {
58 return None;
59 }
60
61 let channel_for_pong = channel.clone();
63 let on_pong = Closure::wrap(Box::new(move |event: web_sys::MessageEvent| {
64 if let Some(data) = event.data().as_string()
65 && data == "ping"
66 {
67 let _ = channel_for_pong.post_message(&JsValue::from_str("pong"));
68 }
69 }) as Box<dyn FnMut(_)>);
70
71 channel.set_onmessage(Some(on_pong.as_ref().unchecked_ref()));
72 on_pong.forget();
73
74 Some(TabLock { _channel: channel })
75 }
76
77 #[cfg(not(target_arch = "wasm32"))]
79 pub fn try_acquire(_lock_name: &str) -> Option<Self> {
80 Some(TabLock { _nop: () })
81 }
82}
83
84#[cfg(target_arch = "wasm32")]
85impl Drop for TabLock {
86 fn drop(&mut self) {
87 self._channel.close();
88 }
89}