1use alloc::rc::Rc;
68use alloc::rc::Weak;
69use alloc::string::String;
70
71use wasm_bindgen02::JsCast;
72use wasm_bindgen02::closure::Closure;
73use web_sys03::js_sys::{ArrayBuffer, Math, Uint8Array};
74use web_sys03::{BinaryType, CloseEvent, ErrorEvent, MessageEvent, WebSocket, Window, window};
75
76use crate::api::Mode;
77use crate::web::{
78 Connect, EmptyCallback, Error, Location, ServiceBuilder, Shared, SocketImpl, WebImpl,
79 WindowImpl,
80};
81
82pub mod prelude {
83 pub mod ws {
86 pub use crate::api::ChannelId;
90 pub use crate::web::{
91 Call, ChannelEvent, Connect, EmptyCallback, Error, KeyedRequests, Listener, Packet,
92 RawPacket, Request, Requests, State, StateListener,
93 };
94
95 use crate::web03::Web03Impl;
96
97 pub fn connect(connect: Connect) -> ServiceBuilder<EmptyCallback> {
101 crate::web03::connect(connect)
102 }
103
104 pub type Service = crate::web::Service<Web03Impl>;
108
109 pub type Handle = crate::web::Handle<Web03Impl>;
113
114 pub type Channel = crate::web::Channel<Web03Impl>;
118
119 pub type RequestBuilder<'a, B, C> = crate::web::RequestBuilder<'a, Web03Impl, B, C>;
123
124 pub type ServiceBuilder<C> = crate::web::ServiceBuilder<Web03Impl, C>;
128 }
129}
130
131#[doc(hidden)]
133pub struct Handles {
134 close: Closure<dyn Fn(CloseEvent)>,
135 message: Closure<dyn Fn(MessageEvent)>,
136 error: Closure<dyn Fn(ErrorEvent)>,
137}
138
139#[derive(Clone, Copy)]
143pub enum Web03Impl {}
144
145impl crate::web::sealed_socket::Sealed for WebSocket {}
146
147impl SocketImpl for WebSocket {
148 type Handles = Handles;
149
150 #[inline]
151 fn new(url: &str, handles: &Self::Handles) -> Result<Self, Error> {
152 let this = WebSocket::new(url)?;
153 this.set_binary_type(BinaryType::Arraybuffer);
154 this.set_onclose(Some(handles.close.as_ref().unchecked_ref()));
155 this.set_onmessage(Some(handles.message.as_ref().unchecked_ref()));
156 this.set_onerror(Some(handles.error.as_ref().unchecked_ref()));
157 Ok(this)
158 }
159
160 #[inline]
161 fn send(&self, mode: Mode, data: &[u8]) -> Result<(), Error> {
162 match mode {
163 Mode::Binary => {
164 self.send_with_u8_array(data)?;
165 }
166 Mode::Text => {
167 self.send_with_str(&String::from_utf8_lossy(data))?;
171 }
172 }
173
174 Ok(())
175 }
176
177 #[inline]
178 fn close(self) -> Result<(), Error> {
179 WebSocket::set_onclose(&self, None);
182 WebSocket::set_onmessage(&self, None);
183 WebSocket::set_onerror(&self, None);
184 WebSocket::close(&self)?;
185 Ok(())
186 }
187}
188
189impl crate::web::sealed_window::Sealed for Window {}
190
191impl WindowImpl for Window {
192 type Timeout = Timeout;
193 type OnBeforeUnload = Event;
194
195 #[inline]
196 fn new() -> Result<Self, Error> {
197 let Some(window) = window() else {
198 return Err(Error::message("No window in web-sys 0.3.x context"));
199 };
200
201 Ok(window)
202 }
203
204 #[inline]
205 fn location(&self) -> Result<Location, Error> {
206 let location = Window::location(self);
207
208 Ok(Location {
209 protocol: location.protocol()?,
210 host: location.hostname()?,
211 port: location.port()?,
212 })
213 }
214
215 #[inline]
216 fn onbeforeunload(&self, callback: impl Fn() + 'static) -> Result<Self::OnBeforeUnload, Error> {
217 let closure = Closure::new(callback);
218 window()
219 .unwrap()
220 .set_onbeforeunload(Some(closure.as_ref().unchecked_ref()));
221 Ok(Event { closure })
222 }
223
224 #[inline]
225 fn set_timeout(
226 &self,
227 millis: u32,
228 callback: impl Fn() + 'static,
229 ) -> Result<Self::Timeout, Error> {
230 let closure = Closure::new(callback);
231
232 let id = self.set_timeout_with_callback_and_timeout_and_arguments_0(
233 closure.as_ref().unchecked_ref(),
234 millis as i32,
235 )?;
236
237 Ok(Timeout {
238 window: self.clone(),
239 id: Some(id),
240 closure: Some(closure),
241 })
242 }
243}
244
245pub struct Timeout {
246 window: Window,
247 id: Option<i32>,
248 #[allow(dead_code)]
249 closure: Option<Closure<dyn FnMut()>>,
250}
251
252impl Drop for Timeout {
253 fn drop(&mut self) {
256 if let Some(id) = self.id.take() {
257 self.window.clear_timeout_with_handle(id);
258 }
259 }
260}
261
262pub struct Event {
263 #[allow(dead_code)]
264 closure: Closure<dyn FnMut()>,
265}
266
267impl crate::web::sealed_web::Sealed for Web03Impl {}
268
269impl WebImpl for Web03Impl {
270 type Window = Window;
271 type Handles = Handles;
272 type Socket = WebSocket;
273
274 #[inline]
275 fn random(range: u32) -> u32 {
276 ((Math::random() * range as f64).round() as u32).min(range)
277 }
278
279 #[inline]
280 #[allow(private_interfaces)]
281 fn handles(shared: &Weak<Shared<Self>>) -> Self::Handles {
282 let close = {
283 let shared = shared.clone();
284
285 Closure::new(move |e: CloseEvent| {
286 if let Some(shared) = shared.upgrade() {
287 shared.web03_close(e);
288 }
289 })
290 };
291
292 let message = {
293 let shared = shared.clone();
294
295 Closure::new(move |e: MessageEvent| {
296 if let Some(shared) = shared.upgrade() {
297 shared.web03_message(e);
298 }
299 })
300 };
301
302 let error = {
303 let shared = shared.clone();
304
305 Closure::new(move |e: ErrorEvent| {
306 if let Some(shared) = shared.upgrade() {
307 shared.web03_error(e);
308 }
309 })
310 };
311
312 Self::Handles {
313 close,
314 message,
315 error,
316 }
317 }
318}
319
320#[inline]
323pub fn connect(connect: Connect) -> ServiceBuilder<Web03Impl, EmptyCallback> {
324 crate::web::connect(connect)
325}
326
327impl Shared<Web03Impl> {
328 fn web03_close(self: &Rc<Self>, e: CloseEvent) {
329 tracing::debug!(code = e.code(), reason = e.reason(), "Close event");
330
331 if let Err(e) = self.close_and_reconnect() {
332 self.on_error.call(e);
333 }
334 }
335
336 fn web03_message(self: &Rc<Shared<Web03Impl>>, e: MessageEvent) {
337 tracing::debug!("Message event");
338
339 let data = e.data();
340
341 let result = if let Some(text) = data.as_string() {
344 self.text_message(&text)
345 } else {
346 let Ok(array_buffer) = data.dyn_into::<ArrayBuffer>() else {
347 self.on_error
348 .call(Error::message("Expected message as ArrayBuffer or string"));
349 return;
350 };
351
352 let array = Uint8Array::new(&array_buffer);
353 let needed = array.length() as usize;
354
355 let mut buf = self.next_buffer(needed);
356
357 unsafe {
360 array.raw_copy_to_ptr(buf.data.as_mut_ptr());
361 buf.data.set_len(needed);
362 }
363
364 self.message(Mode::Binary, buf)
365 };
366
367 if let Err(e) = result {
368 self.on_error.call(e);
369 }
370 }
371
372 fn web03_error(self: &Rc<Self>, e: ErrorEvent) {
373 tracing::debug!(message = e.message(), "Error event");
374
375 if let Err(e) = self.close_and_reconnect() {
376 self.on_error.call(e);
377 }
378 }
379}