summaryrefslogtreecommitdiff
path: root/src/net/client.rs
blob: d9936e5c8c53314a657d26282b285efbe5cc7509 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
use std::{collections::VecDeque, sync::{Arc, Mutex}};

use wasm_bindgen::prelude::*;

#[derive(Debug)]
pub enum Message {
    Binary(Vec<u8>),
    Text(String),
}

impl Message {
    pub fn from_messageevent(e: web_sys::MessageEvent) -> Self {
        if let Ok(abuf) = e.data().dyn_into::<js_sys::ArrayBuffer>() {
            let array = js_sys::Uint8Array::new(&abuf).to_vec();
            Message::Binary(array)
        } else if let Ok(txt) = e.data().dyn_into::<js_sys::JsString>() {
            Message::Text(txt.into())
        } else {
            panic!("received weird websocked message: {:?}", e);
        }
    }
}

pub struct Client {
    pub ws: Option<web_sys::WebSocket>,
    pub messages: Arc<Mutex<VecDeque<Message>>>,
}

impl Client {
    pub fn new() -> Self {
        Self {
            ws: None,
            messages: Arc::new(Mutex::new(VecDeque::new())),
        }
    }
    pub fn connect(&mut self, url: &str) {
        let ws = web_sys::WebSocket::new(url).expect("failed to open websocket");
        let messages_ref = self.messages.clone();
        let cb: Closure<dyn Fn(web_sys::MessageEvent)> = Closure::new(move |e: web_sys::MessageEvent| {
            let msg = Message::from_messageevent(e);
            log::info!("incoming: {:?}", msg);
            messages_ref.lock().unwrap().push_back(msg);
        });
        ws.set_onmessage(Some(cb.as_ref().unchecked_ref()));
        cb.forget();
        self.ws = Some(ws);
    }
    pub fn poll(&mut self) -> Option<Message> {
        self.messages.lock().unwrap().pop_front()
    }
    pub fn send(&self, msg: Message) {
        if let Some(ws) = &self.ws {
            match msg {
                Message::Text(txt) => {
                    if let Err(e) = ws.send_with_str(&txt) {
                        log::warn!("failed to send string: {:?}", e);
                    }
                },
                Message::Binary(bytes) => {
                    if let Err(e) = ws.send_with_u8_array(&bytes) {
                        log::warn!("failed to send bytes: {:?}", e);
                    }
                },
            }
        }
    }
}