1#[cfg(target_arch = "wasm32")]
4pub(crate) mod js_web_socket {
5 use std::net::ToSocketAddrs;
6
7 use sapp_jsutils::JsObject;
8
9 use crate::error::Error;
10
11 pub struct WebSocket;
12
13 extern "C" {
14 fn ws_connect(addr: JsObject);
15 fn ws_send(buffer: JsObject);
16 fn ws_try_recv() -> JsObject;
17 fn ws_is_connected() -> i32;
18 }
19
20 impl WebSocket {
21 pub fn send_text(&self, text: &str) {
22 unsafe { ws_send(JsObject::string(text)) };
23 }
24
25 pub fn send_bytes(&self, data: &[u8]) {
26 unsafe { ws_send(JsObject::buffer(data)) };
27 }
28
29 pub fn try_recv(&mut self) -> Option<Vec<u8>> {
30 let data = unsafe { ws_try_recv() };
31 if data.is_nil() == false {
32 let is_text = data.field_u32("text") == 1;
33 let mut buf = vec![];
34 if is_text {
35 let mut s = String::new();
36 data.field("data").to_string(&mut s);
37 buf = s.into_bytes();
38 } else {
39 data.to_byte_buffer(&mut buf);
40 }
41 return Some(buf);
42 }
43 None
44 }
45
46 pub fn connected(&self) -> bool {
47 unsafe { ws_is_connected() == 1 }
48 }
49
50 pub fn connect<A: ToSocketAddrs + std::fmt::Display>(addr: A) -> Result<WebSocket, Error> {
51 unsafe { ws_connect(JsObject::string(&format!("{}", addr))) };
52
53 Ok(WebSocket)
54 }
55 }
56}
57
58#[cfg(not(target_arch = "wasm32"))]
59mod pc_web_socket {
60 use std::net::ToSocketAddrs;
61 use std::sync::{mpsc, Mutex};
62
63 use crate::error::Error;
64
65 pub struct WebSocket {
66 sender: ws::Sender,
67 rx: Mutex<mpsc::Receiver<Event>>,
68 }
69
70 enum Event {
71 Connect(ws::Sender),
72 Message(Vec<u8>),
73 }
74
75 struct Client {
76 out: ws::Sender,
77 thread_out: mpsc::Sender<Event>,
78 }
79
80 impl ws::Handler for Client {
81 fn on_open(&mut self, _: ws::Handshake) -> ws::Result<()> {
82 self.thread_out
83 .send(Event::Connect(self.out.clone()))
84 .unwrap();
85 Ok(())
86 }
87
88 fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
89 self.thread_out
90 .send(Event::Message(msg.into_data()))
91 .unwrap();
92 Ok(())
93 }
94
95 fn on_close(&mut self, code: ws::CloseCode, _reason: &str) {
96 println!("closed {:?}", code);
97 }
98
99 fn on_error(&mut self, error: ws::Error) {
100 println!("{:?}", error);
101 }
102 }
103
104 impl WebSocket {
105 pub fn connect<A: ToSocketAddrs + std::fmt::Display>(addr: A) -> Result<WebSocket, Error> {
106 let (tx, rx) = mpsc::channel();
107 let ws_addr = format!("{}", addr);
108 std::thread::spawn(move || {
109 ws::connect(ws_addr, |out| Client {
110 out,
111 thread_out: tx.clone(),
112 })
113 .unwrap()
114 });
115
116 match rx.recv() {
117 Ok(Event::Connect(sender)) => Ok(WebSocket {
118 sender,
119 rx: Mutex::new(rx),
120 }),
121 _ => panic!("Failed to connect websocket"),
122 }
123 }
124
125 pub fn connected(&self) -> bool {
126 true
127 }
128
129 pub fn try_recv(&mut self) -> Option<Vec<u8>> {
130 self.rx
131 .lock()
132 .unwrap()
133 .try_recv()
134 .ok()
135 .map(|event| match event {
136 Event::Message(msg) => msg,
137 _ => panic!(),
138 })
139 }
140
141 pub fn send_text(&self, text: &str) {
142 self.sender.send(ws::Message::text(text)).unwrap();
143 }
144
145 pub fn send_bytes(&self, data: &[u8]) {
146 self.sender
147 .send(ws::Message::Binary(data.to_vec()))
148 .unwrap();
149 }
150 }
151}
152
153#[cfg(target_arch = "wasm32")]
154pub use js_web_socket::WebSocket;
155
156#[cfg(not(target_arch = "wasm32"))]
157pub use pc_web_socket::WebSocket;