1use std::cell::RefCell;
4use std::rc::Rc;
5use wasm_bindgen::JsCast;
6use wasm_bindgen::prelude::*;
7use web_sys::{CloseEvent, MessageEvent, WebSocket, Window};
8
9use crate::waterfall::Waterfall;
10
11pub struct WebSocketClient {}
17
18struct WebSocketData {
19 url: String,
20 onmessage: JsValue,
22 onclose: RefCell<Option<JsValue>>,
27}
28
29impl WebSocketClient {
30 pub fn start(window: &Window, waterfall: Rc<RefCell<Waterfall>>) -> Result<(), JsValue> {
39 let location = window.location();
40 let protocol = if location.protocol()? == "https:" {
41 "wss"
42 } else {
43 "ws"
44 };
45 let hostname = location.hostname()?;
46 let port = location.port()?;
47 let data = Rc::new(WebSocketData {
48 url: format!("{protocol}://{hostname}:{port}/waterfall"),
49 onmessage: onmessage(waterfall).into_js_value(),
50 onclose: RefCell::new(None),
51 });
52 data.setup_onclose();
53 data.connect()?;
55 Ok(())
56 }
57}
58
59fn onmessage(waterfall: Rc<RefCell<Waterfall>>) -> Closure<dyn Fn(MessageEvent)> {
60 Closure::new(move |event: MessageEvent| {
61 let data = match event.data().dyn_into::<js_sys::ArrayBuffer>() {
62 Ok(x) => x,
63 Err(e) => {
64 web_sys::console::error_1(&e);
65 return;
66 }
67 };
68 waterfall
69 .borrow_mut()
70 .put_waterfall_spectrum(&js_sys::Float32Array::new(&data));
71 })
72}
73
74impl WebSocketData {
75 fn connect(&self) -> Result<(), JsValue> {
76 let ws = WebSocket::new(&self.url)?;
77 ws.set_binary_type(web_sys::BinaryType::Arraybuffer);
78 ws.set_onmessage(Some(self.onmessage.unchecked_ref()));
79 ws.set_onclose(Some(
81 self.onclose.borrow().as_ref().unwrap().unchecked_ref(),
82 ));
83 Ok(())
84 }
85
86 fn setup_onclose(self: &Rc<Self>) {
87 let data = Rc::clone(self);
88 let closure = Closure::<dyn Fn(CloseEvent)>::new(move |_: CloseEvent| {
89 data.connect().unwrap();
90 });
91 *self.onclose.borrow_mut() = Some(closure.into_js_value());
92 }
93}