verdigris 0.2.1

Browser application to explore, learn and debug CoAP
//! An own implementation of WebSockets, limited to receiving small binary data
//!
//! This is not using yew's websocket because that coan't do subprotocols and has been removed
//! at some point after 0.18, and not using the yew-websocket crate because that is lagging behind
//! Yew releases, and not using gloo-websockets because it seems that gloo is becoming
//! unmaintained (or is Yew too, anyway?)

use wasm_bindgen::JsCast as _;

pub struct Websocket {
    socket: web_sys::WebSocket,
    // These are never read but merely kept alive so that the registered (necessarily weak because
    // FFI-crossing) functions are kept available.
    #[allow(unused)]
    on_message: wasm_bindgen::closure::Closure<dyn FnMut(web_sys::MessageEvent)>,
    #[allow(unused)]
    on_open: wasm_bindgen::closure::Closure<dyn FnMut(web_sys::Event)>,
    #[allow(unused)]
    on_error: wasm_bindgen::closure::Closure<dyn FnMut(web_sys::Event)>,
    #[allow(unused)]
    on_close: wasm_bindgen::closure::Closure<dyn FnMut(web_sys::Event)>,
}

impl Websocket {
    pub fn new(uri: &str, proto: &str, mut on_message: impl 'static + FnMut(Vec<u8>), mut on_open: impl 'static + FnMut(), mut on_error: impl 'static + FnMut(), mut on_close: impl 'static + FnMut()) -> Result<Self, wasm_bindgen::JsValue> {
        let socket = web_sys::WebSocket::new_with_str(uri, proto)?;

        socket.set_binary_type(web_sys::BinaryType::Arraybuffer);
        let on_message = wasm_bindgen::closure::Closure::<dyn FnMut(_)>::new(move |e: web_sys::MessageEvent| {
            if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
                let array = js_sys::Uint8Array::new(&abuf);
                let vec = array.to_vec();
                on_message(vec);
            } else {
                // Silently ignoring text messages
            }
            });
        socket.set_onmessage(Some(on_message.as_ref().unchecked_ref()));

        let on_open = wasm_bindgen::closure::Closure::<dyn FnMut(_)>::new(move |_: web_sys::Event| {
            on_open()
        });
        socket.set_onopen(Some(on_open.as_ref().unchecked_ref()));

        let on_error = wasm_bindgen::closure::Closure::<dyn FnMut(_)>::new(move |_: web_sys::Event| {
            on_error()
        });
        socket.set_onerror(Some(on_error.as_ref().unchecked_ref()));

        let on_close = wasm_bindgen::closure::Closure::<dyn FnMut(_)>::new(move |_: web_sys::Event| {
            on_close()
        });
        socket.set_onclose(Some(on_close.as_ref().unchecked_ref()));

        Ok(Websocket {
            socket,
            on_message,
            on_open,
            on_error,
            on_close,
        })
    }

    pub fn send_binary(&mut self, data: &[u8]) -> Result<(), wasm_bindgen::JsValue> {
        self.socket.send_with_u8_array(data)
    }
}