oxygengine_editor_tools_backend_web/
broadcast.rs1use js_sys::{Object, Uint8ClampedArray};
2use oxygengine_backend_web::closure::WebClosure;
3use oxygengine_editor_tools::simp::*;
4use std::{cell::RefCell, collections::VecDeque, rc::Rc};
5use wasm_bindgen::{prelude::*, JsCast};
6use web_sys::{BroadcastChannel, MessageEvent};
7
8pub struct WebBroadcastChannel {
9 name: String,
10 channel: BroadcastChannel,
11 callback: WebClosure,
12 messages: Rc<RefCell<VecDeque<SimpMessage>>>,
13}
14
15#[cfg(feature = "web")]
16unsafe impl Send for WebBroadcastChannel {}
17#[cfg(feature = "web")]
18unsafe impl Sync for WebBroadcastChannel {}
19
20impl WebBroadcastChannel {
21 pub fn new(name: impl ToString) -> Self {
22 let name = name.to_string();
23 let channel = BroadcastChannel::new(&name).unwrap();
24 let messages = Rc::new(RefCell::new(VecDeque::default()));
25 let messages2 = Rc::clone(&messages);
26 let closure = Closure::wrap(Box::new(move |event: MessageEvent| {
27 event.prevent_default();
28 let id = js_sys::Reflect::get(&event.data(), &JsValue::from("id"))
29 .unwrap()
30 .as_string()
31 .unwrap();
32 let version = js_sys::Reflect::get(&event.data(), &JsValue::from("version"))
33 .unwrap()
34 .as_f64()
35 .unwrap() as u32;
36 let text_data = js_sys::Reflect::get(&event.data(), &JsValue::from("text"))
37 .ok()
38 .and_then(|text| text.as_string());
39 let binary_data = js_sys::Reflect::get(&event.data(), &JsValue::from("binary"))
40 .ok()
41 .and_then(|binary| binary.dyn_into::<Uint8ClampedArray>().ok())
42 .map(|binary| binary.to_vec());
43 messages2.borrow_mut().push_back(SimpMessage {
44 id: SimpMessageId::new(id, version),
45 text_data,
46 binary_data,
47 });
48 }) as Box<dyn FnMut(_)>);
49 channel
50 .add_event_listener_with_callback("message", closure.as_ref().unchecked_ref())
51 .unwrap();
52 Self {
53 name,
54 channel,
55 callback: WebClosure::acquire(closure),
56 messages,
57 }
58 }
59
60 pub fn name(&self) -> &str {
61 &self.name
62 }
63}
64
65impl Drop for WebBroadcastChannel {
66 fn drop(&mut self) {
67 self.channel.close();
68 self.callback.release();
69 }
70}
71
72impl SimpSender for WebBroadcastChannel {
73 type Error = ();
74
75 fn write(&mut self, message: SimpMessage) -> Result<(), Self::Error> {
76 let SimpMessage {
77 id,
78 text_data,
79 binary_data,
80 } = message;
81 let SimpMessageId { id, version } = id;
82 let result = Object::new();
83 js_sys::Reflect::set(&result, &JsValue::from("id"), &JsValue::from(id)).unwrap();
84 js_sys::Reflect::set(
85 &result,
86 &JsValue::from("version"),
87 &JsValue::from(version as f64),
88 )
89 .unwrap();
90 if let Some(text_data) = text_data {
91 js_sys::Reflect::set(&result, &JsValue::from("text"), &JsValue::from(text_data))
92 .unwrap();
93 }
94 if let Some(binary_data) = binary_data {
95 let buffer = Uint8ClampedArray::new_with_length(binary_data.len() as _);
96 buffer.copy_from(&binary_data);
97 js_sys::Reflect::set(&result, &JsValue::from("binary"), &buffer).unwrap();
98 }
99 self.channel.post_message(&result).map_err(|_| ())
100 }
101}
102
103impl SimpReceiver for WebBroadcastChannel {
104 type Error = ();
105
106 fn read(&mut self) -> Option<Result<SimpMessage, Self::Error>> {
107 self.messages.borrow_mut().pop_front().map(Ok)
108 }
109}
110
111impl SimpChannel for WebBroadcastChannel {}