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