Skip to main content

musli_web/
web.rs

1//! The generic web implementation.
2//!
3//! This is specialized over the `H` parameter through modules such as:
4//!
5//! * [`web03`] for `web-sys` `0.3.x`.
6//!
7//! [`web03`]: crate::web03
8
9use core::cell::{Cell, RefCell};
10use core::marker::PhantomData;
11use core::mem;
12use core::ops::Deref;
13use core::ptr::NonNull;
14use core::{any, fmt};
15use std::collections::VecDeque;
16
17use alloc::boxed::Box;
18use alloc::format;
19use alloc::rc::Rc;
20use alloc::rc::Weak;
21use alloc::string::{String, ToString};
22use alloc::vec::Vec;
23
24use std::collections::hash_map::{Entry, HashMap};
25
26use slab::Slab;
27
28use crate::api::{self, ChannelId, DecodeBody, Event, Format, MessageId};
29use crate::format;
30
31const MAX_CAPACITY: usize = 1048576;
32
33/// An empty request body.
34#[non_exhaustive]
35pub struct EmptyBody;
36
37/// An empty callback.
38#[non_exhaustive]
39pub struct EmptyCallback;
40
41trait RequestCallback {
42    fn error(&self, error: Error);
43
44    fn as_request(&self) -> Option<&(dyn Callback<Result<RawPacket, Error>> + 'static)> {
45        None
46    }
47
48    fn as_channel(&self) -> Option<&(dyn Fn(Result<ChannelId, Error>) + 'static)> {
49        None
50    }
51
52    /// The format this is a negotiation for, if it is one.
53    fn as_negotiate(&self) -> Option<Format> {
54        None
55    }
56}
57
58/// The pending callback used for a format negotiation issued by the service
59/// itself.
60struct NegotiateCallback(Format);
61
62impl RequestCallback for NegotiateCallback {
63    #[inline]
64    fn as_negotiate(&self) -> Option<Format> {
65        Some(self.0)
66    }
67
68    #[inline]
69    fn error(&self, error: Error) {
70        tracing::debug!("Format negotiation failed: {error}");
71    }
72}
73
74/// Slab of state listeners.
75type StateListeners = Slab<Rc<dyn Callback<State>>>;
76/// Slab of broadcast listeners.
77type Broadcasts = HashMap<MessageId, Slab<Rc<dyn Callback<Result<RawPacket>>>>>;
78/// Queue of recycled buffers.
79type Buffers = VecDeque<Box<BufData>>;
80/// Pending requests.
81type Requests = HashMap<u32, Box<Pending<dyn RequestCallback>>>;
82
83/// Location information for WebSocket implementation.
84#[doc(hidden)]
85pub struct Location {
86    pub(crate) protocol: String,
87    pub(crate) host: String,
88    pub(crate) port: String,
89}
90
91pub(crate) mod sealed_socket {
92    pub trait Sealed {}
93}
94
95pub(crate) trait SocketImpl
96where
97    Self: Sized + self::sealed_socket::Sealed,
98{
99    #[doc(hidden)]
100    type Handles;
101
102    #[doc(hidden)]
103    fn new(url: &str, handles: &Self::Handles) -> Result<Self, Error>;
104
105    #[doc(hidden)]
106    fn send(&self, data: &[u8]) -> Result<(), Error>;
107
108    #[doc(hidden)]
109    fn close(self) -> Result<(), Error>;
110}
111
112pub(crate) mod sealed_window {
113    pub trait Sealed {}
114}
115
116pub(crate) trait WindowImpl
117where
118    Self: Sized + self::sealed_window::Sealed,
119{
120    #[doc(hidden)]
121    type Timeout;
122
123    #[doc(hidden)]
124    type OnBeforeUnload;
125
126    #[doc(hidden)]
127    fn new() -> Result<Self, Error>;
128
129    #[doc(hidden)]
130    fn location(&self) -> Result<Location, Error>;
131
132    #[doc(hidden)]
133    fn set_timeout(
134        &self,
135        millis: u32,
136        callback: impl Fn() + 'static,
137    ) -> Result<Self::Timeout, Error>;
138
139    #[doc(hidden)]
140    fn onbeforeunload(&self, callback: impl Fn() + 'static) -> Result<Self::OnBeforeUnload, Error>;
141}
142
143pub(crate) mod sealed_web {
144    pub trait Sealed {}
145}
146
147/// Central trait for web integration.
148///
149/// Since web integration is currently unstable, this requires multiple
150/// different implementations, each time an ecosystem breaking change is
151/// released.
152///
153/// The crate in focus here is `web-sys`, and the corresponding modules provide
154/// integrations:
155///
156/// * [web03] for `web-sys` `0.3.x`.
157///
158/// [web03]: crate::web03
159pub trait WebImpl
160where
161    Self: 'static + Copy + Sized + self::sealed_web::Sealed,
162{
163    #[doc(hidden)]
164    #[allow(private_bounds)]
165    type Window: WindowImpl;
166
167    #[doc(hidden)]
168    type Handles;
169
170    #[doc(hidden)]
171    #[allow(private_bounds)]
172    type Socket: SocketImpl<Handles = Self::Handles>;
173
174    #[doc(hidden)]
175    #[allow(private_interfaces)]
176    fn handles(shared: &Weak<Shared<Self>>) -> Self::Handles;
177
178    #[doc(hidden)]
179    fn random(range: u32) -> u32;
180}
181
182/// Construct a new [`ServiceBuilder`] associated with the given [`Connect`]
183/// strategy.
184pub fn connect<H>(connect: Connect) -> ServiceBuilder<H, EmptyCallback>
185where
186    H: WebImpl,
187{
188    ServiceBuilder {
189        connect,
190        on_error: EmptyCallback,
191        close_before_unload: false,
192        format: Format::DEFAULT,
193        _marker: PhantomData,
194    }
195}
196
197/// The state of the connection.
198///
199/// A listener for state changes can be set up through for example
200/// [`Handle::on_state_change`].
201#[derive(Debug, PartialEq, Eq, Clone, Copy)]
202#[non_exhaustive]
203pub enum State {
204    /// The connection is open.
205    Open,
206    /// The connection is closed.
207    Closed,
208}
209
210impl State {
211    /// Check if the state is open.
212    pub fn is_open(&self) -> bool {
213        matches!(self, Self::Open)
214    }
215}
216
217/// Error type for the WebSocket service.
218#[derive(Debug)]
219pub struct Error {
220    kind: ErrorKind,
221}
222
223impl Error {
224    #[inline]
225    fn new(kind: ErrorKind) -> Self {
226        Self { kind }
227    }
228
229    /// Check if the error is caused by an empty packet.
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use musli_web::web::{Error, RawPacket};
235    ///
236    /// let packet = RawPacket::empty();
237    /// let e = packet.decode::<u32>().unwrap_err();
238    ///
239    /// assert!(e.is_empty_packet());
240    /// ```
241    #[inline]
242    pub fn is_empty_packet(&self) -> bool {
243        matches!(self.kind, ErrorKind::EmptyPacket)
244    }
245
246    /// Format a WebSocket error consisting of a message.
247    #[inline]
248    pub fn message(message: impl fmt::Display) -> Self {
249        Self::new(ErrorKind::Message(message.to_string()))
250    }
251
252    #[inline]
253    pub(crate) fn decode_response_header(error: format::Error) -> Self {
254        Self::new(ErrorKind::DecodeResponseHeader(error))
255    }
256
257    #[inline]
258    pub(crate) fn decode_error_message(error: format::Error) -> Self {
259        Self::new(ErrorKind::DecodeErrorMessage(error))
260    }
261
262    #[inline]
263    pub(crate) fn decode_packet(error: format::Error) -> Self {
264        Self::new(ErrorKind::DecodePacket(error))
265    }
266
267    #[inline]
268    pub(crate) fn encoding_header(error: format::Error) -> Self {
269        Self::new(ErrorKind::EncodingHeader(error))
270    }
271
272    #[inline]
273    pub(crate) fn encoding_body(error: format::Error) -> Self {
274        Self::new(ErrorKind::EncodingBody(error))
275    }
276}
277
278#[derive(Debug)]
279enum ErrorKind {
280    EmptyPacket,
281    Message(String),
282    DecodeResponseHeader(format::Error),
283    DecodeErrorMessage(format::Error),
284    DecodePacket(format::Error),
285    EncodingHeader(format::Error),
286    EncodingBody(format::Error),
287}
288
289impl fmt::Display for Error {
290    #[inline]
291    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292        match &self.kind {
293            ErrorKind::EmptyPacket => write!(f, "Packet is empty"),
294            ErrorKind::Message(message) => write!(f, "{message}"),
295            ErrorKind::DecodeResponseHeader(..) => {
296                write!(f, "Encoding error when decoding response header")
297            }
298            ErrorKind::DecodeErrorMessage(..) => {
299                write!(f, "Encoding error when decoding error response")
300            }
301            ErrorKind::DecodePacket(..) => write!(f, "Encoding error when decoding packet"),
302            ErrorKind::EncodingHeader(..) => write!(f, "Encoding error when encoding header"),
303            ErrorKind::EncodingBody(..) => write!(f, "Encoding error when encoding body"),
304        }
305    }
306}
307
308impl core::error::Error for Error {
309    #[inline]
310    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
311        match &self.kind {
312            ErrorKind::DecodeResponseHeader(error) => Some(error),
313            ErrorKind::DecodeErrorMessage(error) => Some(error),
314            ErrorKind::DecodePacket(error) => Some(error),
315            ErrorKind::EncodingHeader(error) => Some(error),
316            ErrorKind::EncodingBody(error) => Some(error),
317            _ => None,
318        }
319    }
320}
321
322#[cfg(feature = "wasm_bindgen02")]
323impl From<wasm_bindgen02::JsValue> for Error {
324    #[inline]
325    fn from(error: wasm_bindgen02::JsValue) -> Self {
326        Self::new(ErrorKind::Message(format!("{error:?}")))
327    }
328}
329
330type Result<T, E = Error> = core::result::Result<T, E>;
331
332const INITIAL_TIMEOUT: u32 = 250;
333const MAX_TIMEOUT: u32 = 4000;
334
335/// How to connect to the WebSocket.
336#[derive(Debug)]
337enum ConnectKind {
338    Location { path: String },
339    Url { url: String },
340}
341
342/// A specification for how to connect a WebSocket.
343pub struct Connect {
344    kind: ConnectKind,
345}
346
347impl Connect {
348    /// Connect to the same location with a custom path.
349    ///
350    /// Note that any number of `/` prefixes are ignored, the canonical
351    /// representation always ignores them and the path is relative to the
352    /// current location.
353    #[inline]
354    pub fn location(path: impl AsRef<str>) -> Self {
355        Self {
356            kind: ConnectKind::Location {
357                path: String::from(path.as_ref()),
358            },
359        }
360    }
361
362    /// Connect to the specified URL.
363    #[inline]
364    pub fn url(url: String) -> Self {
365        Self {
366            kind: ConnectKind::Url { url },
367        }
368    }
369}
370
371impl fmt::Debug for Connect {
372    #[inline]
373    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374        self.kind.fmt(f)
375    }
376}
377
378/// Generic but shared fields which do not depend on specialization over `H`.
379struct Generic {
380    state_listeners: RefCell<StateListeners>,
381    requests: RefCell<Requests>,
382    broadcasts: RefCell<Broadcasts>,
383    buffers: RefCell<Buffers>,
384}
385
386/// Shared implementation details for WebSocket implementations.
387pub(crate) struct Shared<H>
388where
389    H: WebImpl,
390{
391    connect: Connect,
392    state: Cell<State>,
393    should_be: Cell<State>,
394    connecting: Cell<bool>,
395    /// The format in effect, as agreed by the [negotiation protocol].
396    ///
397    /// [negotiation protocol]: crate::api#negotiating-the-format
398    format: Cell<Format>,
399    /// The format the user asked for, re-negotiated on every reconnect.
400    requested: Format,
401    handle: Handle<H>,
402    pub(crate) on_error: Box<dyn Callback<Error>>,
403    window: H::Window,
404    handles: H::Handles,
405    serial: Cell<u32>,
406    defer_broadcasts: RefCell<VecDeque<Weak<dyn Callback<Result<RawPacket>>>>>,
407    defer_state_listeners: RefCell<VecDeque<Weak<dyn Callback<State>>>>,
408    pub(crate) socket: RefCell<Option<H::Socket>>,
409    output: RefCell<Vec<u8>>,
410    current_timeout: Cell<u32>,
411    reconnect_timeout: RefCell<Option<<H::Window as WindowImpl>::Timeout>>,
412    _window_onbeforeunload: Option<<H::Window as WindowImpl>::OnBeforeUnload>,
413    g: Rc<Generic>,
414}
415
416impl<H> Drop for Shared<H>
417where
418    H: WebImpl,
419{
420    fn drop(&mut self) {
421        if let Some(s) = self.socket.take() {
422            tracing::debug!("Closing connection during drop");
423
424            if let Err(error) = s.close() {
425                self.on_error.call(error);
426            }
427        }
428
429        // We don't need to worry about mutable borrows here, since we only have
430        // weak references to Shared and by virtue of this being dropped they
431        // are all invalid.
432        let state_listeners = mem::take(&mut *self.g.state_listeners.borrow_mut());
433        let mut requests = self.g.requests.borrow_mut();
434
435        for (_, listener) in state_listeners {
436            listener.call(State::Closed);
437        }
438
439        for (_, p) in requests.drain() {
440            p.callback.error(Error::message("Websocket service closed"));
441        }
442    }
443}
444
445/// Builder of a service.
446pub struct ServiceBuilder<H, E>
447where
448    H: WebImpl,
449{
450    connect: Connect,
451    on_error: E,
452    close_before_unload: bool,
453    format: Format,
454    _marker: PhantomData<H>,
455}
456
457impl<H, E> ServiceBuilder<H, E>
458where
459    H: WebImpl,
460    E: Callback<Error>,
461{
462    /// Set the error handler to use for the service.
463    pub fn on_error<U>(self, on_error: U) -> ServiceBuilder<H, U>
464    where
465        U: Callback<Error>,
466    {
467        ServiceBuilder {
468            connect: self.connect,
469            on_error,
470            close_before_unload: self.close_before_unload,
471            format: self.format,
472            _marker: self._marker,
473        }
474    }
475
476    /// Set the [`Format`] to use for message bodies.
477    ///
478    /// The format is negotiated with the server once the connection is
479    /// established, see the [negotiation protocol]. If the server does not
480    /// support it the error is reported through [`ServiceBuilder::on_error`]
481    /// and the connection falls back to [`Format::DEFAULT`], which can be
482    /// observed through [`Handle::format`].
483    ///
484    /// Defaults to [`Format::DEFAULT`].
485    ///
486    /// [negotiation protocol]: crate::api#negotiating-the-format
487    #[inline]
488    pub fn format(mut self, format: Format) -> ServiceBuilder<H, E> {
489        self.format = format;
490        self
491    }
492
493    /// Install an event handler which will try to close the WebSocket
494    /// connection on page unload.
495    ///
496    /// This is not strictly necessary, but some browsers like Firefox might be
497    /// slow to recycle the connection unless it has been explicitly closed.
498    #[inline]
499    pub fn close_before_unload(mut self) -> Self {
500        self.close_before_unload = true;
501        self
502    }
503
504    /// Build a new service and open it.
505    ///
506    /// In order to close or open the service again, see [`Service::close`] and
507    /// [`Service::open`].
508    pub fn build(self) -> Service<H> {
509        let window = match H::Window::new() {
510            Ok(window) => window,
511            Err(error) => {
512                panic!("{error}")
513            }
514        };
515
516        let shared = Rc::<Shared<H>>::new_cyclic(move |shared| {
517            let window_onbeforeunload = if self.close_before_unload {
518                let shared = shared.clone();
519
520                let result = window.onbeforeunload(move || {
521                    tracing::debug!("Trying to close WebSocket connection on page unload");
522
523                    if let Some(shared) = shared.upgrade() {
524                        shared.close();
525                    }
526                });
527
528                match result {
529                    Ok(onbeforeunload) => Some(onbeforeunload),
530                    Err(error) => {
531                        self.on_error.call(Error::message(format_args!(
532                            "Failed to set onbeforeunload: {error}"
533                        )));
534                        None
535                    }
536                }
537            } else {
538                None
539            };
540
541            Shared {
542                connect: self.connect,
543                state: Cell::new(State::Closed),
544                should_be: Cell::new(State::Closed),
545                connecting: Cell::new(false),
546                format: Cell::new(self.format),
547                requested: self.format,
548                handle: Handle {
549                    shared: shared.clone(),
550                },
551                on_error: Box::new(self.on_error),
552                window,
553                handles: H::handles(shared),
554                serial: Cell::new(0),
555                defer_broadcasts: RefCell::new(VecDeque::new()),
556                defer_state_listeners: RefCell::new(VecDeque::new()),
557                socket: RefCell::new(None),
558                output: RefCell::new(Vec::new()),
559                current_timeout: Cell::new(INITIAL_TIMEOUT),
560                reconnect_timeout: RefCell::new(None),
561                _window_onbeforeunload: window_onbeforeunload,
562                g: Rc::new(Generic {
563                    state_listeners: RefCell::new(Slab::new()),
564                    broadcasts: RefCell::new(HashMap::new()),
565                    requests: RefCell::new(Requests::new()),
566                    buffers: RefCell::new(VecDeque::new()),
567                }),
568            }
569        });
570
571        let service = Service { shared };
572        service.open();
573        service
574    }
575}
576
577/// The service handle.
578///
579/// Once dropped this will cause the service to be disconnected and all requests
580/// to be cancelled.
581pub struct Service<H>
582where
583    H: WebImpl,
584{
585    shared: Rc<Shared<H>>,
586}
587
588impl<H> Service<H>
589where
590    H: WebImpl,
591{
592    /// Attempt to establish a WebSocket connection.
593    #[deprecated(since = "0.3.0", note = "Use `open` instead")]
594    pub fn connect(&self) {
595        self.shared.open()
596    }
597
598    /// Open the WebSocket connection.
599    ///
600    /// Calling this method indicates that the connection should stay open, and
601    /// the implementation will attempt to reconnect until [`Service::close`] is
602    /// called.
603    pub fn open(&self) {
604        self.shared.open()
605    }
606
607    /// Close the WebSocket connection.
608    ///
609    /// This is not strictly necessary, but some browsers like Firefox might be
610    /// slow to recycle the connection unless it has been explicitly closed.
611    ///
612    /// It is generally recommended that you call this when `beforeunload` on
613    /// window is fired.
614    pub fn close(&self) {
615        self.shared.close();
616    }
617
618    /// Return the handle to the service.
619    ///
620    /// A [`Handle`] instances does not force the underlying WebSocket to stay
621    /// connected, and is invalidated when [`Service`] is destructed.
622    pub fn handle(&self) -> &Handle<H> {
623        &self.shared.handle
624    }
625}
626
627impl<H> Clone for Service<H>
628where
629    H: WebImpl,
630{
631    #[inline]
632    fn clone(&self) -> Self {
633        Self {
634            shared: self.shared.clone(),
635        }
636    }
637}
638
639impl<H> Shared<H>
640where
641    H: WebImpl,
642{
643    /// Send a client message.
644    fn send_client_request<T>(&self, serial: u32, channel: ChannelId, body: &T) -> Result<()>
645    where
646        T: api::Request,
647    {
648        let Some(ref socket) = *self.socket.borrow() else {
649            return Err(Error::message("Socket is not connected"));
650        };
651
652        let format = self.format.get();
653
654        let header = api::RequestHeader {
655            serial,
656            id: <T::Endpoint as api::Endpoint>::ID.get(),
657            format: format.to_u8(),
658            channel,
659        };
660
661        let out = &mut *self.output.borrow_mut();
662
663        format::encode_envelope(&mut *out, &header).map_err(Error::encoding_header)?;
664        format
665            .encode(&mut *out, body)
666            .map_err(Error::encoding_body)?;
667
668        tracing::debug!(
669            header.serial,
670            ?header.id,
671            len = out.len(),
672            "Sending request"
673        );
674
675        socket.send(out.as_slice())?;
676
677        out.clear();
678        out.shrink_to(MAX_CAPACITY);
679        Ok(())
680    }
681
682    /// Send a client message.
683    fn send_connect(&self, serial: u32) -> Result<()> {
684        let Some(ref socket) = *self.socket.borrow() else {
685            return Err(Error::message("Socket is not connected"));
686        };
687
688        let header = api::RequestHeader {
689            serial,
690            id: MessageId::CONNECT.get(),
691            // NB: Carries no body.
692            format: 0,
693            channel: ChannelId::NONE,
694        };
695
696        let out = &mut *self.output.borrow_mut();
697
698        format::encode_envelope(&mut *out, &header).map_err(Error::encoding_header)?;
699
700        tracing::debug!(
701            header.serial,
702            ?header.id,
703            len = out.len(),
704            "Sending request"
705        );
706
707        socket.send(out.as_slice())?;
708
709        out.clear();
710        out.shrink_to(MAX_CAPACITY);
711        Ok(())
712    }
713
714    /// Ask the server to use the requested format for the rest of the
715    /// connection.
716    fn send_negotiate(self: &Rc<Self>) -> Result<()> {
717        let format = self.requested;
718        let serial = self.serial.get();
719        self.serial.set(serial.wrapping_add(1));
720
721        {
722            let Some(ref socket) = *self.socket.borrow() else {
723                return Err(Error::message("Socket is not connected"));
724            };
725
726            let header = api::RequestHeader {
727                serial,
728                id: MessageId::NEGOTIATE.get(),
729                format: format.to_u8(),
730                // NB: Carries no body.
731                channel: ChannelId::NONE,
732            };
733
734            let out = &mut *self.output.borrow_mut();
735
736            format::encode_envelope(&mut *out, &header).map_err(Error::encoding_header)?;
737
738            tracing::debug!(?format, "Requesting format");
739
740            socket.send(out.as_slice())?;
741
742            out.clear();
743            out.shrink_to(MAX_CAPACITY);
744        }
745
746        let pending = Pending {
747            id: MessageId::NEGOTIATE,
748            serial,
749            callback: NegotiateCallback(format),
750        };
751
752        let existing = self
753            .g
754            .requests
755            .borrow_mut()
756            .insert(serial, Box::new(pending));
757
758        if let Some(p) = existing {
759            p.callback.error(Error::message("Request cancelled"));
760        }
761
762        Ok(())
763    }
764
765    /// Send a disconnect.
766    fn remove_channel(&self, channel: ChannelId) {
767        if let Err(error) = self._send_disconnect(channel) {
768            self.on_error.call(error);
769        }
770    }
771
772    fn _send_disconnect(&self, channel: ChannelId) -> Result<()> {
773        let Some(ref socket) = *self.socket.borrow() else {
774            return Err(Error::message("Socket is not connected"));
775        };
776
777        let header = api::RequestHeader {
778            serial: 0,
779            id: MessageId::DISCONNECT.get(),
780            // NB: Carries no body.
781            format: 0,
782            channel,
783        };
784
785        let out = &mut *self.output.borrow_mut();
786
787        format::encode_envelope(&mut *out, &header).map_err(Error::encoding_header)?;
788
789        tracing::debug!(
790            header.serial,
791            ?header.id,
792            len = out.len(),
793            "Sending request"
794        );
795
796        socket.send(out.as_slice())?;
797
798        out.clear();
799        out.shrink_to(MAX_CAPACITY);
800        Ok(())
801    }
802
803    pub(crate) fn next_buffer(self: &Rc<Self>, needed: usize) -> Box<BufData> {
804        match self.g.buffers.borrow_mut().pop_front() {
805            Some(mut buf) => {
806                if buf.data.capacity() < needed {
807                    buf.data.reserve(needed - buf.data.len());
808                }
809
810                buf
811            }
812            None => Box::new(BufData::with_capacity(Rc::downgrade(&self.g), needed)),
813        }
814    }
815
816    /// Resolve the format a message body is encoded with from its envelope.
817    fn body_format(header: &api::ResponseHeader) -> Result<Format> {
818        let Some(format) = Format::from_u8(header.format) else {
819            return Err(Error::message(format_args!(
820                "Server used unknown format id {} for a message body",
821                header.format
822            )));
823        };
824
825        Ok(format)
826    }
827
828    pub(crate) fn message(self: &Rc<Self>, buf: Box<BufData>) -> Result<()> {
829        // Wrap the buffer in a simple shared reference-counted container.
830        let buf = BufRc::new(buf);
831        let mut at = 0;
832
833        let header: api::ResponseHeader =
834            format::decode_envelope(&buf, &mut at).map_err(Error::decode_response_header)?;
835
836        if let Some(broadcast) = MessageId::new(header.broadcast) {
837            tracing::debug!(?header, "Got broadcast");
838
839            if broadcast == MessageId::SERVER_HELLO {
840                // NB: The connection is not reported as open until the format
841                // has been negotiated, so that server-initiated messages are
842                // never encoded with a format this client did not agree to.
843                tracing::debug!("Server hello, negotiating format");
844                self.send_negotiate()?;
845                return Ok(());
846            }
847
848            if !self.defer_broadcasts(broadcast) {
849                return Ok(());
850            };
851
852            if let Some(id) = MessageId::new(header.error) {
853                let error = match id {
854                    MessageId::ERROR_MESSAGE => Self::body_format(&header)?
855                        .decode(&buf, &mut at)
856                        .map_err(Error::decode_error_message)?,
857                    _ => api::ErrorMessage {
858                        message: "Unsupported broadcast",
859                    },
860                };
861
862                while let Some(callback) = self.defer_broadcasts.borrow_mut().pop_front() {
863                    if let Some(callback) = callback.upgrade() {
864                        callback.call(Err(Error::message(format_args!(
865                            "Server error: {}",
866                            error.message
867                        ))));
868                    }
869                }
870
871                return Ok(());
872            }
873
874            let format = Self::body_format(&header)?;
875
876            let packet = RawPacket {
877                buf: Some(buf.clone()),
878                at: Cell::new(at),
879                id: broadcast,
880                format,
881                channel: header.channel,
882            };
883
884            while let Some(callback) = self.defer_broadcasts.borrow_mut().pop_front() {
885                if let Some(callback) = callback.upgrade() {
886                    callback.call(Ok(packet.clone()));
887                }
888            }
889        } else {
890            tracing::debug!(?header, "Got response");
891            let p = self.g.requests.borrow_mut().remove(&header.serial);
892
893            if let Some(p) = p {
894                if let Some(id) = MessageId::new(header.error) {
895                    let error = match id {
896                        MessageId::ERROR_MESSAGE => Self::body_format(&header)?
897                            .decode(&buf, &mut at)
898                            .map_err(Error::decode_error_message)?,
899                        _ => api::ErrorMessage {
900                            message: "Unsupported request",
901                        },
902                    };
903
904                    if let Some(format) = p.callback.as_negotiate() {
905                        // NB: The server cannot speak the requested format, so
906                        // fall back to the default rather than leaving the
907                        // connection unusable.
908                        self.on_error.call(Error::message(format_args!(
909                            "Server rejected format `{format}` ({}), falling back to `{}`",
910                            error.message,
911                            Format::DEFAULT
912                        )));
913
914                        self.format.set(Format::DEFAULT);
915                        self.emit_state_change(State::Open);
916                        return Ok(());
917                    }
918
919                    p.callback.error(Error::message(format_args!(
920                        "Server error: {}",
921                        error.message
922                    )));
923                    return Ok(());
924                }
925
926                match p.id {
927                    MessageId::NEGOTIATE => {
928                        let Some(requested) = p.callback.as_negotiate() else {
929                            p.callback
930                                .error(Error::message("Unexpected negotiate response"));
931                            return Ok(());
932                        };
933
934                        // NB: Trust the format the server echoed back over the
935                        // one that was asked for, so that a server which
936                        // downgrades is honored.
937                        let accepted = Format::from_u8(header.format).unwrap_or(requested);
938                        tracing::debug!(?accepted, "Format negotiated");
939                        self.format.set(accepted);
940                        self.emit_state_change(State::Open);
941                        return Ok(());
942                    }
943                    MessageId::CONNECT => {
944                        let Some(callback) = &p.callback.as_channel() else {
945                            p.callback
946                                .error(Error::message("Unexpected channel response"));
947                            return Ok(());
948                        };
949
950                        callback(Ok(header.channel));
951                        return Ok(());
952                    }
953                    _ => {
954                        let Some(callback) = p.callback.as_request() else {
955                            p.callback
956                                .error(Error::message("Unexpected channel response"));
957                            return Ok(());
958                        };
959
960                        let format = Self::body_format(&header)?;
961
962                        let packet = RawPacket {
963                            id: p.id,
964                            buf: Some(buf),
965                            at: Cell::new(at),
966                            format,
967                            channel: header.channel,
968                        };
969
970                        callback.call(Ok(packet));
971                        return Ok(());
972                    }
973                }
974            }
975
976            // NB: This is normal, it simply indicates that the handler has been
977            // closed.
978            tracing::trace!(?header.serial, "Got message with unknown serial");
979        }
980
981        Ok(())
982    }
983
984    fn defer_broadcasts(self: &Rc<Self>, kind: MessageId) -> bool {
985        // Note: We need to defer this, since the outcome of calling
986        // the broadcast callback might be that the broadcast
987        // listener is modified, which could require mutable access
988        // to broadcasts.
989        let mut defer = self.defer_broadcasts.borrow_mut();
990
991        let broadcasts = self.g.broadcasts.borrow();
992
993        let Some(broadcasts) = broadcasts.get(&kind) else {
994            return false;
995        };
996
997        for (_, callback) in broadcasts.iter() {
998            defer.push_back(Rc::downgrade(callback));
999        }
1000
1001        !defer.is_empty()
1002    }
1003
1004    pub(crate) fn close_and_reconnect(self: &Rc<Self>) -> Result<(), Error> {
1005        tracing::debug!("Closing and reconnecting");
1006
1007        // We need a weak reference back to shared state to handle the timeout.
1008        let shared = Rc::downgrade(self);
1009
1010        if self.state.get() == State::Closed {
1011            let current_timeout = self.current_timeout.get();
1012
1013            if current_timeout < MAX_TIMEOUT {
1014                let fuzz = H::random(50);
1015
1016                self.current_timeout.set(
1017                    current_timeout
1018                        .saturating_mul(2)
1019                        .saturating_add(fuzz)
1020                        .min(MAX_TIMEOUT),
1021                );
1022            }
1023        } else {
1024            self.current_timeout.set(INITIAL_TIMEOUT);
1025            self.close_once();
1026        }
1027
1028        let timeout = self.current_timeout.get();
1029
1030        tracing::debug!(?timeout, "Setting");
1031
1032        let timeout = self.window.set_timeout(timeout, move || {
1033            if let Some(shared) = shared.upgrade() {
1034                Self::try_once(&shared);
1035            }
1036        })?;
1037
1038        drop(self.reconnect_timeout.borrow_mut().replace(timeout));
1039        self.connecting.set(false);
1040        Ok(())
1041    }
1042
1043    /// Close an pending requests with an error, since there is no chance they
1044    /// will be responded to any more.
1045    fn close_pending(self: &Rc<Self>) {
1046        loop {
1047            let Some(serial) = self.g.requests.borrow().keys().next().copied() else {
1048                break;
1049            };
1050
1051            let p = {
1052                let mut requests = self.g.requests.borrow_mut();
1053
1054                let Some(p) = requests.remove(&serial) else {
1055                    break;
1056                };
1057
1058                p
1059            };
1060
1061            p.callback.error(Error::message("Connection closed"));
1062        }
1063    }
1064
1065    fn emit_state_change(&self, state: State) {
1066        if self.state.get() == state {
1067            return;
1068        }
1069
1070        self.state.set(state);
1071
1072        {
1073            // We need to collect callbacks to avoid the callback recursively
1074            // borrowing state listeners, which it would if it modifies any
1075            // existing state listeners.
1076            let mut defer = self.defer_state_listeners.borrow_mut();
1077
1078            for (_, callback) in self.g.state_listeners.borrow().iter() {
1079                defer.push_back(Rc::downgrade(callback));
1080            }
1081
1082            if defer.is_empty() {
1083                return;
1084            }
1085        }
1086
1087        while let Some(callback) = self.defer_state_listeners.borrow_mut().pop_front() {
1088            if let Some(callback) = callback.upgrade() {
1089                callback.call(state);
1090            }
1091        }
1092    }
1093
1094    #[inline]
1095    fn open(self: &Rc<Self>) {
1096        self.should_be.set(State::Open);
1097        self.try_once();
1098    }
1099
1100    #[inline]
1101    fn close(self: &Rc<Self>) {
1102        self.should_be.set(State::Closed);
1103        self.try_once();
1104    }
1105
1106    fn try_once(self: &Rc<Self>) {
1107        if self.should_be.get() == State::Open && !self.connecting.get() {
1108            tracing::debug!("Trying to open connection");
1109            self.connect_once();
1110        }
1111    }
1112
1113    fn close_once(self: &Rc<Self>) {
1114        self.connecting.set(false);
1115        self.emit_state_change(State::Closed);
1116
1117        if let Some(s) = self.socket.take() {
1118            tracing::debug!("Closing old socket once");
1119
1120            if let Err(error) = s.close() {
1121                self.on_error.call(error);
1122            }
1123        }
1124
1125        self.close_pending();
1126    }
1127
1128    fn connect_once(self: &Rc<Self>) {
1129        self.connecting.set(true);
1130
1131        let url = match &self.connect.kind {
1132            ConnectKind::Location { path } => {
1133                let location = match WindowImpl::location(&self.window) {
1134                    Ok(location) => location,
1135                    Err(e) => {
1136                        self.on_error
1137                            .call(Error::message(format_args!("Could not get location: {e}")));
1138                        self.should_be.set(State::Closed);
1139                        return;
1140                    }
1141                };
1142
1143                let Location {
1144                    protocol,
1145                    host,
1146                    port,
1147                } = location;
1148
1149                let protocol = match protocol.as_str() {
1150                    "https:" => "wss:",
1151                    "http:" => "ws:",
1152                    other => {
1153                        self.on_error.call(Error::message(format_args!(
1154                            "Unsupported protocol `{other}` for same host connection"
1155                        )));
1156
1157                        self.should_be.set(State::Closed);
1158                        return;
1159                    }
1160                };
1161
1162                let path = ForcePrefix(path, '/');
1163                format!("{protocol}//{host}:{port}{path}")
1164            }
1165            ConnectKind::Url { url } => url.clone(),
1166        };
1167
1168        // We explicitly want to close and dispose of the old socket first.
1169        if let Some(s) = self.socket.borrow_mut().take() {
1170            tracing::debug!("Closing old socket");
1171
1172            if let Err(error) = s.close() {
1173                self.on_error.call(error);
1174            }
1175        }
1176
1177        let ws = match SocketImpl::new(&url, &self.handles) {
1178            Ok(ws) => ws,
1179            Err(error) => {
1180                self.on_error.call(error);
1181                self.should_be.set(State::Closed);
1182                return;
1183            }
1184        };
1185
1186        *self.socket.borrow_mut() = Some(ws);
1187    }
1188}
1189
1190/// Trait governing how callbacks are called.
1191pub trait Callback<I>
1192where
1193    Self: 'static,
1194{
1195    /// Call the callback.
1196    fn call(&self, input: I);
1197}
1198
1199impl<I> Callback<I> for EmptyCallback {
1200    #[inline]
1201    fn call(&self, _: I) {}
1202}
1203
1204impl<F, I> Callback<I> for F
1205where
1206    F: 'static + Fn(I),
1207{
1208    #[inline]
1209    fn call(&self, input: I) {
1210        self(input)
1211    }
1212}
1213
1214/// A request builder .
1215///
1216/// Associate the callback to be used by using either
1217/// [`RequestBuilder::on_packet`] or [`RequestBuilder::on_raw_packet`] depending
1218/// on your needs.
1219///
1220/// Send the request with [`RequestBuilder::send`].
1221pub struct ChannelBuilder<'a, H, C>
1222where
1223    H: WebImpl,
1224{
1225    shared: &'a Weak<Shared<H>>,
1226    callback: C,
1227}
1228
1229impl<'a, H, C> ChannelBuilder<'a, H, C>
1230where
1231    H: WebImpl,
1232{
1233    /// Define the handler to be called when a connection is established.
1234    ///
1235    /// # Examples
1236    ///
1237    /// ```
1238    /// # extern crate yew023 as yew;
1239    /// use yew::prelude::*;
1240    /// use musli_web::web03::prelude::*;
1241    ///
1242    /// mod api {
1243    ///     use musli::{Decode, Encode};
1244    ///     use musli_web::api;
1245    ///
1246    ///     #[derive(Encode, Decode)]
1247    ///     pub struct HelloRequest<'de> {
1248    ///         pub message: &'de str,
1249    ///     }
1250    ///
1251    ///     #[derive(Encode, Decode)]
1252    ///     pub struct HelloResponse<'de> {
1253    ///         pub message: &'de str,
1254    ///     }
1255    ///
1256    ///     api::define! {
1257    ///         pub type Hello;
1258    ///
1259    ///         impl Endpoint for Hello {
1260    ///             impl<'de> Request for HelloRequest<'de>;
1261    ///             type Response<'de> = HelloResponse<'de>;
1262    ///         }
1263    ///     }
1264    /// }
1265    ///
1266    /// enum Msg {
1267    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
1268    ///     OnChannel(Result<ws::Channel, ws::Error>),
1269    /// }
1270    ///
1271    /// #[derive(Properties, PartialEq)]
1272    /// struct Props {
1273    ///     ws: ws::Handle,
1274    /// }
1275    ///
1276    /// struct App {
1277    ///     message: String,
1278    ///     _hello: ws::Request,
1279    ///     _channel_open: ws::Request,
1280    ///     channel: ws::Channel,
1281    /// }
1282    ///
1283    /// impl Component for App {
1284    ///     type Message = Msg;
1285    ///     type Properties = Props;
1286    ///
1287    ///     fn create(ctx: &Context<Self>) -> Self {
1288    ///         let link = ctx.link().clone();
1289    ///
1290    ///         let _channel_open = ctx.props().ws
1291    ///             .channel()
1292    ///             .on_open(ctx.link().callback(Msg::OnChannel))
1293    ///             .send();
1294    ///
1295    ///         Self {
1296    ///             message: String::from("No Message :("),
1297    ///             _hello: ws::Request::default(),
1298    ///             _channel_open: _channel_open,
1299    ///             channel: ws::Channel::default(),
1300    ///         }
1301    ///     }
1302    ///
1303    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
1304    ///         match msg {
1305    ///             Msg::OnHello(Err(error)) => {
1306    ///                 tracing::error!("Request error: {:?}", error);
1307    ///                 false
1308    ///             }
1309    ///             Msg::OnHello(Ok(packet)) => {
1310    ///                 if let Ok(response) = packet.decode() {
1311    ///                     self.message = response.message.to_owned();
1312    ///                 }
1313    ///
1314    ///                 true
1315    ///             }
1316    ///             Msg::OnChannel(result) => {
1317    ///                 if let Ok(channel) = result {
1318    ///                     self.channel = channel;
1319    ///                 }
1320    ///
1321    ///                 self._hello = self.channel
1322    ///                     .request()
1323    ///                     .body(api::HelloRequest { message: "Hello!"})
1324    ///                     .on_packet(ctx.link().callback(Msg::OnHello))
1325    ///                     .send();
1326    ///
1327    ///                 true
1328    ///             }
1329    ///         }
1330    ///     }
1331    ///
1332    ///     fn view(&self, ctx: &Context<Self>) -> Html {
1333    ///         html! {
1334    ///             <div>
1335    ///                 <h1>{"WebSocket Example"}</h1>
1336    ///                 <p>{format!("Message: {}", self.message)}</p>
1337    ///             </div>
1338    ///         }
1339    ///     }
1340    /// }
1341    /// ```
1342    pub fn on_open<U>(self, callback: U) -> ChannelBuilder<'a, H, U>
1343    where
1344        U: Callback<Result<Channel<H>, Error>>,
1345    {
1346        ChannelBuilder {
1347            shared: self.shared,
1348            callback,
1349        }
1350    }
1351}
1352
1353impl<'a, H, C> ChannelBuilder<'a, H, C>
1354where
1355    C: Callback<Result<Channel<H>, Error>>,
1356    H: WebImpl,
1357{
1358    /// Send the connection request.
1359    pub fn send(self) -> Request {
1360        struct RequestCallbackImpl<C>(C);
1361
1362        impl<C> RequestCallback for RequestCallbackImpl<C>
1363        where
1364            C: Fn(Result<ChannelId, Error>) + 'static,
1365        {
1366            #[inline]
1367            fn as_channel(&self) -> Option<&(dyn Fn(Result<ChannelId, Error>) + 'static)> {
1368                Some(&self.0)
1369            }
1370
1371            #[inline]
1372            fn error(&self, error: Error) {
1373                (self.0)(Err(error));
1374            }
1375        }
1376
1377        let Some(shared) = self.shared.upgrade() else {
1378            self.callback
1379                .call(Err(Error::message("WebSocket service is down")));
1380            return Request::new();
1381        };
1382
1383        if shared.state.get() != State::Open {
1384            self.callback
1385                .call(Err(Error::message("WebSocket is not connected")));
1386            return Request::new();
1387        }
1388
1389        let serial = shared.serial.get();
1390
1391        if let Err(error) = shared.send_connect(serial) {
1392            shared.on_error.call(error);
1393            return Request::new();
1394        }
1395
1396        shared.serial.set(serial.wrapping_add(1));
1397
1398        let callback = {
1399            let shared = Rc::downgrade(&shared);
1400
1401            move |result| {
1402                let result = match result {
1403                    Err(error) => Err(error),
1404                    Ok(id) => Ok(Channel {
1405                        handle: Handle {
1406                            shared: shared.clone(),
1407                        },
1408                        id,
1409                    }),
1410                };
1411
1412                self.callback.call(result)
1413            }
1414        };
1415
1416        let pending = Pending {
1417            id: MessageId::CONNECT,
1418            serial,
1419            callback: RequestCallbackImpl(callback),
1420        };
1421
1422        let existing = shared
1423            .g
1424            .requests
1425            .borrow_mut()
1426            .insert(serial, Box::new(pending));
1427
1428        if let Some(p) = existing {
1429            p.callback.error(Error::message("Request cancelled"));
1430        }
1431
1432        Request {
1433            serial,
1434            g: Rc::downgrade(&shared.g),
1435        }
1436    }
1437}
1438
1439/// A request builder .
1440///
1441/// Associate the callback to be used by using either
1442/// [`RequestBuilder::on_packet`] or [`RequestBuilder::on_raw_packet`] depending
1443/// on your needs.
1444///
1445/// Send the request with [`RequestBuilder::send`].
1446pub struct RequestBuilder<'a, H, B, C>
1447where
1448    H: WebImpl,
1449{
1450    shared: &'a Weak<Shared<H>>,
1451    channel: Option<ChannelId>,
1452    body: B,
1453    callback: C,
1454}
1455
1456impl<'a, H, B, C> RequestBuilder<'a, H, B, C>
1457where
1458    H: WebImpl,
1459{
1460    /// Set the body of the request.
1461    #[inline]
1462    pub fn body<U>(self, body: U) -> RequestBuilder<'a, H, U, C>
1463    where
1464        U: api::Request,
1465    {
1466        RequestBuilder {
1467            shared: self.shared,
1468            channel: self.channel,
1469            body,
1470            callback: self.callback,
1471        }
1472    }
1473
1474    /// Handle the response using the specified callback.
1475    ///
1476    /// # Examples
1477    ///
1478    /// ```
1479    /// # extern crate yew023 as yew;
1480    /// use yew::prelude::*;
1481    /// use musli_web::web03::prelude::*;
1482    ///
1483    /// mod api {
1484    ///     use musli::{Decode, Encode};
1485    ///     use musli_web::api;
1486    ///
1487    ///     #[derive(Encode, Decode)]
1488    ///     pub struct HelloRequest<'de> {
1489    ///         pub message: &'de str,
1490    ///     }
1491    ///
1492    ///     #[derive(Encode, Decode)]
1493    ///     pub struct HelloResponse<'de> {
1494    ///         pub message: &'de str,
1495    ///     }
1496    ///
1497    ///     api::define! {
1498    ///         pub type Hello;
1499    ///
1500    ///         impl Endpoint for Hello {
1501    ///             impl<'de> Request for HelloRequest<'de>;
1502    ///             type Response<'de> = HelloResponse<'de>;
1503    ///         }
1504    ///     }
1505    /// }
1506    ///
1507    /// enum Msg {
1508    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
1509    /// }
1510    ///
1511    /// #[derive(Properties, PartialEq)]
1512    /// struct Props {
1513    ///     ws: ws::Handle,
1514    /// }
1515    ///
1516    /// struct App {
1517    ///     message: String,
1518    ///     _hello: ws::Request,
1519    /// }
1520    ///
1521    /// impl Component for App {
1522    ///     type Message = Msg;
1523    ///     type Properties = Props;
1524    ///
1525    ///     fn create(ctx: &Context<Self>) -> Self {
1526    ///         let hello = ctx.props().ws
1527    ///             .request()
1528    ///             .body(api::HelloRequest { message: "Hello!"})
1529    ///             .on_packet(ctx.link().callback(Msg::OnHello))
1530    ///             .send();
1531    ///
1532    ///         Self {
1533    ///             message: String::from("No Message :("),
1534    ///             _hello: hello,
1535    ///         }
1536    ///     }
1537    ///
1538    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
1539    ///         match msg {
1540    ///             Msg::OnHello(Err(error)) => {
1541    ///                 tracing::error!("Request error: {:?}", error);
1542    ///                 false
1543    ///             }
1544    ///             Msg::OnHello(Ok(packet)) => {
1545    ///                 if let Ok(response) = packet.decode() {
1546    ///                     self.message = response.message.to_owned();
1547    ///                 }
1548    ///
1549    ///                 true
1550    ///             }
1551    ///         }
1552    ///     }
1553    ///
1554    ///     fn view(&self, ctx: &Context<Self>) -> Html {
1555    ///         html! {
1556    ///             <div>
1557    ///                 <h1>{"WebSocket Example"}</h1>
1558    ///                 <p>{format!("Message: {}", self.message)}</p>
1559    ///             </div>
1560    ///         }
1561    ///     }
1562    /// }
1563    /// ```
1564    pub fn on_packet<E>(
1565        self,
1566        callback: impl Callback<Result<Packet<E>>>,
1567    ) -> RequestBuilder<'a, H, B, impl Callback<Result<RawPacket>>>
1568    where
1569        E: api::Endpoint,
1570    {
1571        self.on_raw_packet(move |result: Result<RawPacket>| match result {
1572            Ok(ok) => callback.call(Ok(Packet::new(ok))),
1573            Err(err) => callback.call(Err(err)),
1574        })
1575    }
1576
1577    /// Handle the response using the specified callback.
1578    ///
1579    /// # Examples
1580    ///
1581    /// ```
1582    /// # extern crate yew023 as yew;
1583    /// use yew::prelude::*;
1584    /// use musli_web::web03::prelude::*;
1585    ///
1586    /// mod api {
1587    ///     use musli::{Decode, Encode};
1588    ///     use musli_web::api;
1589    ///
1590    ///     #[derive(Encode, Decode)]
1591    ///     pub struct HelloRequest<'de> {
1592    ///         pub message: &'de str,
1593    ///     }
1594    ///
1595    ///     #[derive(Encode, Decode)]
1596    ///     pub struct HelloResponse<'de> {
1597    ///         pub message: &'de str,
1598    ///     }
1599    ///
1600    ///     api::define! {
1601    ///         pub type Hello;
1602    ///
1603    ///         impl Endpoint for Hello {
1604    ///             impl<'de> Request for HelloRequest<'de>;
1605    ///             type Response<'de> = HelloResponse<'de>;
1606    ///         }
1607    ///     }
1608    /// }
1609    ///
1610    /// enum Msg {
1611    ///     OnHello(Result<ws::RawPacket, ws::Error>),
1612    /// }
1613    ///
1614    /// #[derive(Properties, PartialEq)]
1615    /// struct Props {
1616    ///     ws: ws::Handle,
1617    /// }
1618    ///
1619    /// struct App {
1620    ///     message: String,
1621    ///     _hello: ws::Request,
1622    /// }
1623    ///
1624    /// impl Component for App {
1625    ///     type Message = Msg;
1626    ///     type Properties = Props;
1627    ///
1628    ///     fn create(ctx: &Context<Self>) -> Self {
1629    ///         let link = ctx.link().clone();
1630    ///
1631    ///         let hello = ctx.props().ws
1632    ///             .request()
1633    ///             .body(api::HelloRequest { message: "Hello!"})
1634    ///             .on_raw_packet(move |packet| link.send_message(Msg::OnHello(packet)))
1635    ///             .send();
1636    ///
1637    ///         Self {
1638    ///             message: String::from("No Message :("),
1639    ///             _hello: hello,
1640    ///         }
1641    ///     }
1642    ///
1643    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
1644    ///         match msg {
1645    ///             Msg::OnHello(Err(error)) => {
1646    ///                 tracing::error!("Request error: {:?}", error);
1647    ///                 false
1648    ///             }
1649    ///             Msg::OnHello(Ok(packet)) => {
1650    ///                 if let Ok(response) = packet.decode::<api::HelloResponse>() {
1651    ///                     self.message = response.message.to_owned();
1652    ///                 }
1653    ///
1654    ///                 true
1655    ///             }
1656    ///         }
1657    ///     }
1658    ///
1659    ///     fn view(&self, ctx: &Context<Self>) -> Html {
1660    ///         html! {
1661    ///             <div>
1662    ///                 <h1>{"WebSocket Example"}</h1>
1663    ///                 <p>{format!("Message: {}", self.message)}</p>
1664    ///             </div>
1665    ///         }
1666    ///     }
1667    /// }
1668    /// ```
1669    pub fn on_raw_packet<U>(self, callback: U) -> RequestBuilder<'a, H, B, U>
1670    where
1671        U: Callback<Result<RawPacket, Error>>,
1672    {
1673        RequestBuilder {
1674            shared: self.shared,
1675            channel: self.channel,
1676            body: self.body,
1677            callback,
1678        }
1679    }
1680}
1681
1682impl<'a, H, B, C> RequestBuilder<'a, H, B, C>
1683where
1684    B: api::Request,
1685    C: Callback<Result<RawPacket>>,
1686    H: WebImpl,
1687{
1688    /// Send the request.
1689    ///
1690    /// This requires that a body has been set using [`RequestBuilder::body`].
1691    pub fn send(self) -> Request {
1692        struct RequestCallbackImpl<C>(C);
1693
1694        impl<C> RequestCallback for RequestCallbackImpl<C>
1695        where
1696            C: Callback<Result<RawPacket>>,
1697        {
1698            #[inline]
1699            fn as_request(&self) -> Option<&(dyn Callback<Result<RawPacket>> + 'static)> {
1700                Some(&self.0)
1701            }
1702
1703            #[inline]
1704            fn error(&self, error: Error) {
1705                self.0.call(Err(error));
1706            }
1707        }
1708
1709        let Some(shared) = self.shared.upgrade() else {
1710            self.callback
1711                .call(Err(Error::message("WebSocket service is down")));
1712            return Request::new();
1713        };
1714
1715        if shared.state.get() != State::Open {
1716            self.callback
1717                .call(Err(Error::message("WebSocket is not connected")));
1718            return Request::new();
1719        }
1720
1721        let Some(channel) = self.channel else {
1722            self.callback
1723                .call(Err(Error::message("WebSocket request over closed channel")));
1724            return Request::new();
1725        };
1726
1727        let serial = shared.serial.get();
1728
1729        if let Err(error) = shared.send_client_request(serial, channel, &self.body) {
1730            shared.on_error.call(error);
1731            return Request::new();
1732        }
1733
1734        shared.serial.set(serial.wrapping_add(1));
1735
1736        let pending = Pending {
1737            id: <B::Endpoint as api::Endpoint>::ID,
1738            serial,
1739            callback: RequestCallbackImpl(self.callback),
1740        };
1741
1742        let existing = shared
1743            .g
1744            .requests
1745            .borrow_mut()
1746            .insert(serial, Box::new(pending));
1747
1748        if let Some(p) = existing {
1749            p.callback.error(Error::message("Request cancelled"));
1750        }
1751
1752        Request {
1753            serial,
1754            g: Rc::downgrade(&shared.g),
1755        }
1756    }
1757}
1758
1759/// The handle for a pending request.
1760///
1761/// Dropping or [`clear()`] this handle will cancel the request.
1762///
1763/// [`clear()`]: Self::clear
1764pub struct Request {
1765    serial: u32,
1766    g: Weak<Generic>,
1767}
1768
1769impl Request {
1770    /// An empty request handler.
1771    ///
1772    /// # Examples
1773    ///
1774    /// ```
1775    /// use musli_web::web03::prelude::*;
1776    ///
1777    /// let mut request = ws::Request::new();
1778    /// assert_eq!(request.is_pending(), false);
1779    /// ```
1780    #[inline]
1781    pub const fn new() -> Self {
1782        Self {
1783            serial: 0,
1784            g: Weak::new(),
1785        }
1786    }
1787
1788    /// Clear the request handle without dropping it, cancelling any pending
1789    /// requests.
1790    pub fn clear(&mut self) {
1791        let removed = {
1792            let serial = mem::take(&mut self.serial);
1793
1794            let Some(g) = self.g.upgrade() else {
1795                return;
1796            };
1797
1798            self.g = Weak::new();
1799
1800            let Some(p) = g.requests.borrow_mut().remove(&serial) else {
1801                return;
1802            };
1803
1804            p
1805        };
1806
1807        drop(removed);
1808    }
1809
1810    /// Indicates if a request is pending.
1811    ///
1812    /// # Examples
1813    ///
1814    /// ```
1815    /// use musli_web::web03::prelude::*;
1816    ///
1817    /// let mut request = ws::Request::new();
1818    /// assert_eq!(request.is_pending(), false);
1819    /// ```
1820    #[inline]
1821    pub fn is_pending(&self) -> bool {
1822        let Some(g) = self.g.upgrade() else {
1823            return false;
1824        };
1825
1826        g.requests.borrow().contains_key(&self.serial)
1827    }
1828}
1829
1830impl Default for Request {
1831    #[inline]
1832    fn default() -> Self {
1833        Self::new()
1834    }
1835}
1836
1837impl Drop for Request {
1838    #[inline]
1839    fn drop(&mut self) {
1840        self.clear();
1841    }
1842}
1843
1844/// The handle for a pending request.
1845///
1846/// Dropping or calling [`clear()`] on this handle remove the listener.
1847///
1848/// [`clear()`]: Self::clear
1849pub struct Listener {
1850    kind: Option<MessageId>,
1851    index: usize,
1852    g: Weak<Generic>,
1853}
1854
1855impl Listener {
1856    /// Construct an empty listener.
1857    #[inline]
1858    pub const fn new() -> Self {
1859        Self {
1860            kind: None,
1861            index: 0,
1862            g: Weak::new(),
1863        }
1864    }
1865
1866    /// Build up an empty listener with the specified kind.
1867    #[inline]
1868    pub(crate) const fn empty_with_kind(kind: MessageId) -> Self {
1869        Self {
1870            kind: Some(kind),
1871            index: 0,
1872            g: Weak::new(),
1873        }
1874    }
1875
1876    /// Clear the listener without dropping it.
1877    ///
1878    /// This will remove the associated broadcast listener from being notified.
1879    pub fn clear(&mut self) {
1880        // Gather values here to drop them outside of the upgrade block.
1881        let removed;
1882        let removed_value;
1883
1884        {
1885            let Some(g) = self.g.upgrade() else {
1886                return;
1887            };
1888
1889            self.g = Weak::new();
1890            let index = mem::take(&mut self.index);
1891
1892            let Some(kind) = self.kind.take() else {
1893                return;
1894            };
1895
1896            let mut broadcasts = g.broadcasts.borrow_mut();
1897
1898            let Entry::Occupied(mut e) = broadcasts.entry(kind) else {
1899                return;
1900            };
1901
1902            removed = e.get_mut().try_remove(index);
1903
1904            if e.get().is_empty() {
1905                removed_value = Some(e.remove());
1906            } else {
1907                removed_value = None;
1908            }
1909        }
1910
1911        // Drop here, to avoid invoking any destructors which might borrow
1912        // shared mutably earlier.
1913        drop(removed);
1914        drop(removed_value);
1915    }
1916}
1917
1918impl Default for Listener {
1919    #[inline]
1920    fn default() -> Self {
1921        Self::new()
1922    }
1923}
1924
1925impl Drop for Listener {
1926    #[inline]
1927    fn drop(&mut self) {
1928        self.clear();
1929    }
1930}
1931
1932/// The handle for state change listening.
1933///
1934/// Dropping or calling [`clear()`] on this handle will remove the associated
1935/// callback from being notified.
1936///
1937/// [`clear()`]: Self::clear
1938pub struct StateListener {
1939    index: usize,
1940    g: Weak<Generic>,
1941}
1942
1943impl StateListener {
1944    /// Construct an empty state listener.
1945    #[inline]
1946    pub const fn new() -> Self {
1947        Self {
1948            index: 0,
1949            g: Weak::new(),
1950        }
1951    }
1952
1953    /// Clear the state listener without dropping it.
1954    ///
1955    /// This will remove the associated callback from being notified.
1956    pub fn clear(&mut self) {
1957        let removed = {
1958            let Some(g) = self.g.upgrade() else {
1959                return;
1960            };
1961
1962            self.g = Weak::new();
1963
1964            g.state_listeners.borrow_mut().try_remove(self.index)
1965        };
1966
1967        drop(removed);
1968    }
1969}
1970
1971impl Default for StateListener {
1972    #[inline]
1973    fn default() -> Self {
1974        Self::new()
1975    }
1976}
1977
1978impl Drop for StateListener {
1979    #[inline]
1980    fn drop(&mut self) {
1981        self.clear();
1982    }
1983}
1984
1985pub(crate) struct BufData {
1986    /// Buffer being used.
1987    pub(crate) data: Vec<u8>,
1988    /// Number of strong references to this buffer.
1989    strong: Cell<usize>,
1990    /// Reference to shared state where the buffer will be recycled to.
1991    g: Weak<Generic>,
1992}
1993
1994impl BufData {
1995    fn with_capacity(g: Weak<Generic>, capacity: usize) -> Self {
1996        Self {
1997            data: Vec::with_capacity(capacity),
1998            strong: Cell::new(0),
1999            g,
2000        }
2001    }
2002
2003    unsafe fn dec(ptr: NonNull<BufData>) {
2004        unsafe {
2005            let count = ptr.as_ref().strong.get().wrapping_sub(1);
2006            ptr.as_ref().strong.set(count);
2007
2008            if count > 0 {
2009                return;
2010            }
2011
2012            let mut buf = Box::from_raw(ptr.as_ptr());
2013
2014            // Try to recycle the buffer if shared is available, else let it be
2015            // dropped and free here.
2016            let Some(g) = buf.as_ref().g.upgrade() else {
2017                return;
2018            };
2019
2020            let mut buffers = g.buffers.borrow_mut();
2021
2022            // Set the length of the recycled buffer.
2023            buf.data.set_len(buf.data.len().min(MAX_CAPACITY));
2024
2025            // We size our buffers to some max capacity to avod overuse in case
2026            // we infrequently need to handle some massive message. If we don't
2027            // shrink the allocation, then memory use can run away over time.
2028            buf.data.shrink_to(MAX_CAPACITY);
2029
2030            buffers.push_back(buf);
2031        }
2032    }
2033
2034    unsafe fn inc(ptr: NonNull<BufData>) {
2035        unsafe {
2036            let count = ptr.as_ref().strong.get().wrapping_add(1);
2037
2038            if count == 0 {
2039                std::process::abort();
2040            }
2041
2042            ptr.as_ref().strong.set(count);
2043        }
2044    }
2045}
2046
2047/// A shared buffer of data that is recycled when dropped.
2048struct BufRc {
2049    data: NonNull<BufData>,
2050}
2051
2052impl BufRc {
2053    fn new(data: Box<BufData>) -> Self {
2054        let data = NonNull::from(Box::leak(data));
2055
2056        unsafe {
2057            BufData::inc(data);
2058        }
2059
2060        Self { data }
2061    }
2062}
2063
2064impl Deref for BufRc {
2065    type Target = [u8];
2066
2067    fn deref(&self) -> &Self::Target {
2068        unsafe { &(*self.data.as_ptr()).data }
2069    }
2070}
2071
2072impl Clone for BufRc {
2073    fn clone(&self) -> Self {
2074        unsafe {
2075            BufData::inc(self.data);
2076        }
2077
2078        Self { data: self.data }
2079    }
2080}
2081
2082impl Drop for BufRc {
2083    fn drop(&mut self) {
2084        unsafe {
2085            BufData::dec(self.data);
2086        }
2087    }
2088}
2089
2090/// A raw packet of data.
2091#[derive(Clone)]
2092pub struct RawPacket {
2093    id: MessageId,
2094    buf: Option<BufRc>,
2095    at: Cell<usize>,
2096    format: Format,
2097    channel: ChannelId,
2098}
2099
2100impl RawPacket {
2101    /// Construct an empty raw packet.
2102    ///
2103    /// # Examples
2104    ///
2105    /// ```
2106    /// use musli_web::api::MessageId;
2107    /// use musli_web::web::RawPacket;
2108    ///
2109    /// let packet = RawPacket::empty();
2110    ///
2111    /// assert!(packet.is_empty());
2112    /// assert_eq!(packet.id(), MessageId::EMPTY);
2113    /// ```
2114    pub const fn empty() -> Self {
2115        Self {
2116            id: MessageId::EMPTY,
2117            buf: None,
2118            at: Cell::new(0),
2119            format: Format::DEFAULT,
2120            channel: ChannelId::NONE,
2121        }
2122    }
2123
2124    /// The [`Format`] the body of this packet is encoded with.
2125    ///
2126    /// # Examples
2127    ///
2128    /// ```
2129    /// use musli_web::api::Format;
2130    /// use musli_web::web::RawPacket;
2131    ///
2132    /// let packet = RawPacket::empty();
2133    /// assert_eq!(packet.format(), Format::DEFAULT);
2134    /// ```
2135    #[inline]
2136    pub fn format(&self) -> Format {
2137        self.format
2138    }
2139
2140    /// Return the connection this packet belongs to.
2141    ///
2142    /// This is [`ChannelId::NONE`] unless the packet belongs to a response to a
2143    /// handle constructed with [`Handle::channel`].
2144    #[inline]
2145    pub fn channel(&self) -> ChannelId {
2146        self.channel
2147    }
2148
2149    /// Decode the contents of a raw packet.
2150    ///
2151    /// This can be called multiple times if there are multiple payloads in
2152    /// sequence of the response.
2153    ///
2154    /// You can check if the packet is empty using [`RawPacket::is_empty`].
2155    pub fn decode<'this, T>(&'this self) -> Result<T>
2156    where
2157        T: DecodeBody<'this>,
2158    {
2159        if self.id == MessageId::EMPTY {
2160            return Err(Error::new(ErrorKind::EmptyPacket));
2161        }
2162
2163        let mut at = self.at.get();
2164
2165        match self.format.decode(self.as_slice(), &mut at) {
2166            Ok(value) => {
2167                self.at.set(at);
2168                Ok(value)
2169            }
2170            Err(error) => {
2171                self.at.set(self.len());
2172                Err(Error::decode_packet(error))
2173            }
2174        }
2175    }
2176
2177    /// Get the underlying byte slice of the packet.
2178    ///
2179    /// # Examples
2180    ///
2181    /// ```
2182    /// use musli_web::web::RawPacket;
2183    ///
2184    /// let packet = RawPacket::empty();
2185    /// assert_eq!(packet.as_slice(), &[0u8; 0]);
2186    /// ```
2187    pub fn as_slice(&self) -> &[u8] {
2188        match &self.buf {
2189            Some(buf) => buf.as_ref(),
2190            None => &[],
2191        }
2192    }
2193
2194    /// Get the number of bytes remaining to be decoded in the packet.
2195    ///
2196    /// # Examples
2197    ///
2198    /// ```
2199    /// use musli_web::web::RawPacket;
2200    ///
2201    /// let packet = RawPacket::empty();
2202    /// assert_eq!(packet.remaining(), 0);
2203    /// ```
2204    pub fn remaining(&self) -> usize {
2205        self.as_slice().len().saturating_sub(self.at.get())
2206    }
2207
2208    /// Get the length of the packet.
2209    ///
2210    /// # Examples
2211    ///
2212    /// ```
2213    /// use musli_web::web::RawPacket;
2214    ///
2215    /// let packet = RawPacket::empty();
2216    /// assert_eq!(packet.len(), 0);
2217    /// ```
2218    pub fn len(&self) -> usize {
2219        match &self.buf {
2220            Some(buf) => buf.len(),
2221            None => 0,
2222        }
2223    }
2224
2225    /// Check if the packet is empty.
2226    ///
2227    /// # Examples
2228    ///
2229    /// ```
2230    /// use musli_web::web::RawPacket;
2231    ///
2232    /// let packet = RawPacket::empty();
2233    /// assert!(packet.is_empty());
2234    /// ```
2235    pub fn is_empty(&self) -> bool {
2236        self.at.get() >= self.len()
2237    }
2238
2239    /// The id of the packet this is a response to as specified by
2240    /// [`Endpoint::ID`] or [`Broadcast::ID`].
2241    ///
2242    /// [`Endpoint::ID`]: crate::api::Endpoint::ID
2243    /// [`Broadcast::ID`]: crate::api::Broadcast::ID
2244    pub fn id(&self) -> MessageId {
2245        self.id
2246    }
2247}
2248
2249impl fmt::Debug for RawPacket {
2250    #[inline]
2251    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2252        f.debug_struct("RawPacket")
2253            .field("remaining", &self.remaining())
2254            .finish()
2255    }
2256}
2257
2258/// A typed packet of data.
2259pub struct Packet<T> {
2260    raw: RawPacket,
2261    _marker: PhantomData<T>,
2262}
2263
2264impl<T> Packet<T> {
2265    /// Construct an empty package.
2266    ///
2267    /// # Examples
2268    ///
2269    /// ```
2270    /// use musli_web::api::MessageId;
2271    /// use musli_web::web::Packet;
2272    ///
2273    /// let packet = Packet::<()>::empty();
2274    ///
2275    /// assert!(packet.is_empty());
2276    /// assert_eq!(packet.id(), MessageId::EMPTY);
2277    /// ```
2278    pub const fn empty() -> Self {
2279        Self {
2280            raw: RawPacket::empty(),
2281            _marker: PhantomData,
2282        }
2283    }
2284
2285    /// Return the connection this packet belongs to.
2286    ///
2287    /// This is [`ChannelId::NONE`] unless the packet belongs to a response to a
2288    /// handle constructed with [`Handle::channel`].
2289    #[inline]
2290    pub fn channel(&self) -> ChannelId {
2291        self.raw.channel()
2292    }
2293
2294    /// The [`Format`] the body of this packet is encoded with.
2295    #[inline]
2296    pub fn format(&self) -> Format {
2297        self.raw.format()
2298    }
2299
2300    /// Construct a new typed package from a raw one.
2301    ///
2302    /// Note that this does not guarantee that the typed package is correct, but
2303    /// the `T` parameter becomes associated with it allowing it to be used
2304    /// automatically with methods such as [`Packet::decode`].
2305    #[inline]
2306    pub fn new(raw: RawPacket) -> Self {
2307        Self {
2308            raw,
2309            _marker: PhantomData,
2310        }
2311    }
2312
2313    /// Convert a packet into a raw packet.
2314    ///
2315    /// To determine which endpoint or broadcast it belongs to the
2316    /// [`RawPacket::id`] method can be used.
2317    pub fn into_raw(self) -> RawPacket {
2318        self.raw
2319    }
2320
2321    /// Get the number of bytes remaining to be decoded in the packet.
2322    ///
2323    /// # Examples
2324    ///
2325    /// ```
2326    /// use musli_web::web::Packet;
2327    ///
2328    /// let packet = Packet::<()>::empty();
2329    /// assert_eq!(packet.remaining(), 0);
2330    /// ```
2331    pub fn remaining(&self) -> usize {
2332        self.raw.remaining()
2333    }
2334
2335    /// Check if the packet is empty.
2336    ///
2337    /// # Examples
2338    ///
2339    /// ```
2340    /// use musli_web::web::Packet;
2341    ///
2342    /// let packet = Packet::<()>::empty();
2343    /// assert!(packet.is_empty());
2344    /// ```
2345    pub fn is_empty(&self) -> bool {
2346        self.raw.is_empty()
2347    }
2348
2349    /// The id of the packet this is a response to as specified by
2350    /// [`Endpoint::ID`] or [`Broadcast::ID`].
2351    ///
2352    /// [`Endpoint::ID`]: crate::api::Endpoint::ID
2353    /// [`Broadcast::ID`]: crate::api::Broadcast::ID
2354    pub fn id(&self) -> MessageId {
2355        self.raw.id()
2356    }
2357}
2358
2359impl<T> Packet<T>
2360where
2361    T: api::Decodable,
2362{
2363    /// Decode the contents of a packet.
2364    ///
2365    /// This can be called multiple times if there are multiple payloads in
2366    /// sequence of the response.
2367    ///
2368    /// You can check if the packet is empty using [`Packet::is_empty`].
2369    pub fn decode(&self) -> Result<T::Type<'_>> {
2370        self.decode_any()
2371    }
2372
2373    /// Decode any contents of a packet.
2374    ///
2375    /// This can be called multiple times if there are multiple payloads in
2376    /// sequence of the response.
2377    ///
2378    /// You can check if the packet is empty using [`Packet::is_empty`].
2379    pub fn decode_any<'de, R>(&'de self) -> Result<R>
2380    where
2381        R: DecodeBody<'de>,
2382    {
2383        self.raw.decode()
2384    }
2385}
2386
2387impl<T> Packet<T>
2388where
2389    T: api::Endpoint,
2390{
2391    /// Decode the contents of a packet.
2392    ///
2393    /// This can be called multiple times if there are multiple payloads in
2394    /// sequence of the response.
2395    ///
2396    /// You can check if the packet is empty using [`Packet::is_empty`].
2397    pub fn decode_response(&self) -> Result<T::Response<'_>> {
2398        self.decode_any_response()
2399    }
2400
2401    /// Decode any contents of a packet.
2402    ///
2403    /// This can be called multiple times if there are multiple payloads in
2404    /// sequence of the response.
2405    ///
2406    /// You can check if the packet is empty using [`Packet::is_empty`].
2407    pub fn decode_any_response<'de, R>(&'de self) -> Result<R>
2408    where
2409        R: DecodeBody<'de>,
2410    {
2411        self.raw.decode()
2412    }
2413}
2414
2415impl<T> Packet<T>
2416where
2417    T: api::Broadcast,
2418{
2419    /// Decode the primary event related to a broadcast.
2420    pub fn decode_event<'de>(&'de self) -> Result<T::Event<'de>>
2421    where
2422        T: api::BroadcastWithEvent,
2423    {
2424        self.decode_event_any()
2425    }
2426
2427    /// Decode any event related to a broadcast.
2428    pub fn decode_event_any<'de, E>(&'de self) -> Result<E>
2429    where
2430        E: Event<Broadcast = T> + DecodeBody<'de>,
2431    {
2432        self.raw.decode()
2433    }
2434}
2435
2436impl<T> Clone for Packet<T> {
2437    #[inline]
2438    fn clone(&self) -> Self {
2439        Self {
2440            raw: self.raw.clone(),
2441            _marker: PhantomData,
2442        }
2443    }
2444}
2445
2446impl<T> fmt::Debug for Packet<T> {
2447    #[inline]
2448    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2449        f.debug_struct("Packet")
2450            .field("type", &any::type_name::<T>())
2451            .field("remaining", &self.remaining())
2452            .finish()
2453    }
2454}
2455
2456/// A handle to the WebSocket service.
2457pub struct Handle<H>
2458where
2459    H: WebImpl,
2460{
2461    shared: Weak<Shared<H>>,
2462}
2463
2464impl<H> Handle<H>
2465where
2466    H: WebImpl,
2467{
2468    /// Open a new logical channel to the WebSocket server.
2469    ///
2470    /// A channel can be uniquely identified on the client and server side over
2471    /// a single connection. This means that if you send a request over a
2472    /// channel using [`Channel::request`], the server can access the
2473    /// [`ChannelId`] to determine which channel sent the request and the client
2474    /// has the ability to correlate any responses sent by the server by
2475    /// inspecting [`Packet::channel`] or [`RawPacket::channel`].
2476    ///
2477    /// The [`ChannelId`] can also be sent out-of-bounds, for example as part of
2478    /// the body of a [`ws::Server::broadcast`] allowing the client to filter
2479    /// broadcasts that originated from itself to avoid bouncing updates.
2480    ///
2481    /// The maximum number of channels is implementation defined, but expect it
2482    /// to be relatively low like `65535` (non-zero 16 bits) to reduce payload
2483    /// sizes. Failure to allocate a channel is an error.
2484    ///
2485    /// [`ws::Server::broadcast`]: crate::ws::Server::broadcast
2486    ///
2487    /// # Examples
2488    ///
2489    /// ```
2490    /// # extern crate yew023 as yew;
2491    /// use yew::prelude::*;
2492    /// use musli_web::web03::prelude::*;
2493    ///
2494    /// enum Msg {
2495    ///     OnChannel(Result<ws::Channel, ws::Error>),
2496    /// }
2497    ///
2498    /// #[derive(Properties, PartialEq)]
2499    /// struct Props {
2500    ///     ws: ws::Handle,
2501    /// }
2502    ///
2503    /// struct App {
2504    ///     _channel_open: ws::Request,
2505    ///     channel: ws::Channel,
2506    /// }
2507    ///
2508    /// impl Component for App {
2509    ///     type Message = Msg;
2510    ///     type Properties = Props;
2511    ///
2512    ///     fn create(ctx: &Context<Self>) -> Self {
2513    ///         let link = ctx.link().clone();
2514    ///
2515    ///         let _channel_open = ctx.props().ws
2516    ///             .channel()
2517    ///             .on_open(ctx.link().callback(Msg::OnChannel))
2518    ///             .send();
2519    ///
2520    ///         Self {
2521    ///             _channel_open: _channel_open,
2522    ///             channel: ws::Channel::default(),
2523    ///         }
2524    ///     }
2525    ///
2526    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2527    ///         match msg {
2528    ///             Msg::OnChannel(result) => {
2529    ///                 if let Ok(channel) = result {
2530    ///                     self.channel = channel;
2531    ///                 }
2532    ///
2533    ///                 true
2534    ///             }
2535    ///         }
2536    ///     }
2537    ///
2538    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2539    ///         html! {
2540    ///             <div>
2541    ///                 <h1>{"WebSocket Example"}</h1>
2542    ///             </div>
2543    ///         }
2544    ///     }
2545    /// }
2546    /// ```
2547    /// The [`Format`] currently in effect for message bodies.
2548    ///
2549    /// Before the connection has been opened this is the format which was
2550    /// requested through [`ServiceBuilder::format`]. Once the connection is
2551    /// open it is the format the server actually agreed to, which can differ if
2552    /// the server does not support what was asked for.
2553    pub fn format(&self) -> Format {
2554        let Some(shared) = self.shared.upgrade() else {
2555            return Format::DEFAULT;
2556        };
2557
2558        shared.format.get()
2559    }
2560
2561    pub fn channel(&self) -> ChannelBuilder<'_, H, EmptyCallback> {
2562        ChannelBuilder {
2563            shared: &self.shared,
2564            callback: EmptyCallback,
2565        }
2566    }
2567
2568    /// Send a request of type `T`.
2569    ///
2570    /// Returns a handle for the request.
2571    ///
2572    /// If the handle is dropped, the request is cancelled.
2573    ///
2574    /// # Examples
2575    ///
2576    /// ```
2577    /// # extern crate yew023 as yew;
2578    /// use yew::prelude::*;
2579    /// use musli_web::web03::prelude::*;
2580    ///
2581    /// mod api {
2582    ///     use musli::{Decode, Encode};
2583    ///     use musli_web::api;
2584    ///
2585    ///     #[derive(Encode, Decode)]
2586    ///     pub struct HelloRequest<'de> {
2587    ///         pub message: &'de str,
2588    ///     }
2589    ///
2590    ///     #[derive(Encode, Decode)]
2591    ///     pub struct HelloResponse<'de> {
2592    ///         pub message: &'de str,
2593    ///     }
2594    ///
2595    ///     api::define! {
2596    ///         pub type Hello;
2597    ///
2598    ///         impl Endpoint for Hello {
2599    ///             impl<'de> Request for HelloRequest<'de>;
2600    ///             type Response<'de> = HelloResponse<'de>;
2601    ///         }
2602    ///     }
2603    /// }
2604    ///
2605    /// enum Msg {
2606    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
2607    /// }
2608    ///
2609    /// #[derive(Properties, PartialEq)]
2610    /// struct Props {
2611    ///     ws: ws::Handle,
2612    /// }
2613    ///
2614    /// struct App {
2615    ///     message: String,
2616    ///     _hello: ws::Request,
2617    /// }
2618    ///
2619    /// impl Component for App {
2620    ///     type Message = Msg;
2621    ///     type Properties = Props;
2622    ///
2623    ///     fn create(ctx: &Context<Self>) -> Self {
2624    ///         let hello = ctx.props().ws
2625    ///             .request()
2626    ///             .body(api::HelloRequest { message: "Hello!"})
2627    ///             .on_packet(ctx.link().callback(Msg::OnHello))
2628    ///             .send();
2629    ///
2630    ///         Self {
2631    ///             message: String::from("No Message :("),
2632    ///             _hello: hello,
2633    ///         }
2634    ///     }
2635    ///
2636    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2637    ///         match msg {
2638    ///             Msg::OnHello(Err(error)) => {
2639    ///                 tracing::error!("Request error: {:?}", error);
2640    ///                 false
2641    ///             }
2642    ///             Msg::OnHello(Ok(packet)) => {
2643    ///                 if let Ok(response) = packet.decode() {
2644    ///                     self.message = response.message.to_owned();
2645    ///                 }
2646    ///
2647    ///                 true
2648    ///             }
2649    ///         }
2650    ///     }
2651    ///
2652    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2653    ///         html! {
2654    ///             <div>
2655    ///                 <h1>{"WebSocket Example"}</h1>
2656    ///                 <p>{format!("Message: {}", self.message)}</p>
2657    ///             </div>
2658    ///         }
2659    ///     }
2660    /// }
2661    /// ```
2662    pub fn request(&self) -> RequestBuilder<'_, H, EmptyBody, EmptyCallback> {
2663        RequestBuilder {
2664            shared: &self.shared,
2665            channel: Some(ChannelId::NONE),
2666            body: EmptyBody,
2667            callback: EmptyCallback,
2668        }
2669    }
2670
2671    /// Listen for broadcasts of type `T`.
2672    ///
2673    /// Returns a handle for the listener that will cancel the listener if
2674    /// dropped.
2675    ///
2676    /// # Examples
2677    ///
2678    /// ```
2679    /// # extern crate yew023 as yew;
2680    /// use yew::prelude::*;
2681    /// use musli_web::web03::prelude::*;
2682    ///
2683    /// mod api {
2684    ///     use musli::{Decode, Encode};
2685    ///     use musli_web::api;
2686    ///
2687    ///     #[derive(Encode, Decode)]
2688    ///     pub struct TickEvent<'de> {
2689    ///         pub message: &'de str,
2690    ///         pub tick: u32,
2691    ///     }
2692    ///
2693    ///     api::define! {
2694    ///         pub type Tick;
2695    ///
2696    ///         impl Broadcast for Tick {
2697    ///             impl<'de> Event for TickEvent<'de>;
2698    ///         }
2699    ///     }
2700    /// }
2701    ///
2702    /// enum Msg {
2703    ///     Tick(Result<ws::Packet<api::Tick>, ws::Error>),
2704    /// }
2705    ///
2706    /// #[derive(Properties, PartialEq)]
2707    /// struct Props {
2708    ///     ws: ws::Handle,
2709    /// }
2710    ///
2711    /// struct App {
2712    ///     tick: u32,
2713    ///     _listen: ws::Listener,
2714    /// }
2715    ///
2716    /// impl Component for App {
2717    ///     type Message = Msg;
2718    ///     type Properties = Props;
2719    ///
2720    ///     fn create(ctx: &Context<Self>) -> Self {
2721    ///         let listen = ctx.props().ws.on_broadcast(ctx.link().callback(Msg::Tick));
2722    ///
2723    ///         Self {
2724    ///             tick: 0,
2725    ///             _listen: listen,
2726    ///         }
2727    ///     }
2728    ///
2729    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2730    ///         match msg {
2731    ///             Msg::Tick(Err(error)) => {
2732    ///                 tracing::error!("Tick error: {error}");
2733    ///                 false
2734    ///             }
2735    ///             Msg::Tick(Ok(packet)) => {
2736    ///                 if let Ok(tick) = packet.decode_event() {
2737    ///                     self.tick = tick.tick;
2738    ///                 }
2739    ///
2740    ///                 true
2741    ///             }
2742    ///         }
2743    ///     }
2744    ///
2745    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2746    ///         html! {
2747    ///             <div>
2748    ///                 <h1>{"WebSocket Example"}</h1>
2749    ///                 <p>{format!("Tick: {}", self.tick)}</p>
2750    ///             </div>
2751    ///         }
2752    ///     }
2753    /// }
2754    /// ```
2755    pub fn on_broadcast<T>(&self, callback: impl Callback<Result<Packet<T>>>) -> Listener
2756    where
2757        T: api::Broadcast,
2758    {
2759        self.on_raw_broadcast::<T>(move |result| match result {
2760            Ok(packet) => callback.call(Ok(Packet::new(packet))),
2761            Err(error) => callback.call(Err(error)),
2762        })
2763    }
2764
2765    /// Listen for broadcasts of type `T`.
2766    ///
2767    /// Returns a handle for the listener that will cancel the listener if
2768    /// dropped.
2769    ///
2770    /// # Examples
2771    ///
2772    /// ```
2773    /// # extern crate yew023 as yew;
2774    /// use yew::prelude::*;
2775    /// use musli_web::web03::prelude::*;
2776    ///
2777    /// mod api {
2778    ///     use musli::{Decode, Encode};
2779    ///     use musli_web::api;
2780    ///
2781    ///     #[derive(Encode, Decode)]
2782    ///     pub struct TickEvent<'de> {
2783    ///         pub message: &'de str,
2784    ///         pub tick: u32,
2785    ///     }
2786    ///
2787    ///     api::define! {
2788    ///         pub type Tick;
2789    ///
2790    ///         impl Broadcast for Tick {
2791    ///             impl<'de> Event for TickEvent<'de>;
2792    ///         }
2793    ///     }
2794    /// }
2795    ///
2796    /// enum Msg {
2797    ///     Tick(Result<ws::RawPacket, ws::Error>),
2798    /// }
2799    ///
2800    /// #[derive(Properties, PartialEq)]
2801    /// struct Props {
2802    ///     ws: ws::Handle,
2803    /// }
2804    ///
2805    /// struct App {
2806    ///     tick: u32,
2807    ///     _listen: ws::Listener,
2808    /// }
2809    ///
2810    /// impl Component for App {
2811    ///     type Message = Msg;
2812    ///     type Properties = Props;
2813    ///
2814    ///     fn create(ctx: &Context<Self>) -> Self {
2815    ///         let link = ctx.link().clone();
2816    ///         let listen = ctx.props().ws.on_raw_broadcast::<api::Tick>(ctx.link().callback(Msg::Tick));
2817    ///
2818    ///         Self {
2819    ///             tick: 0,
2820    ///             _listen: listen,
2821    ///         }
2822    ///     }
2823    ///
2824    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2825    ///         match msg {
2826    ///             Msg::Tick(Err(error)) => {
2827    ///                 tracing::error!("Tick error: {error}");
2828    ///                 false
2829    ///             }
2830    ///             Msg::Tick(Ok(packet)) => {
2831    ///                 if let Ok(tick) = packet.decode::<api::TickEvent>() {
2832    ///                     self.tick = tick.tick;
2833    ///                 }
2834    ///
2835    ///                 true
2836    ///             }
2837    ///         }
2838    ///     }
2839    ///
2840    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2841    ///         html! {
2842    ///             <div>
2843    ///                 <h1>{"WebSocket Example"}</h1>
2844    ///                 <p>{format!("Tick: {}", self.tick)}</p>
2845    ///             </div>
2846    ///         }
2847    ///     }
2848    /// }
2849    /// ```
2850    pub fn on_raw_broadcast<T>(&self, callback: impl Callback<Result<RawPacket>>) -> Listener
2851    where
2852        T: api::Broadcast,
2853    {
2854        let Some(shared) = self.shared.upgrade() else {
2855            return Listener::empty_with_kind(T::ID);
2856        };
2857
2858        let index = {
2859            let mut broadcasts = shared.g.broadcasts.borrow_mut();
2860            let slots = broadcasts.entry(T::ID).or_default();
2861            slots.insert(Rc::new(callback))
2862        };
2863
2864        Listener {
2865            kind: Some(T::ID),
2866            index,
2867            g: Rc::downgrade(&shared.g),
2868        }
2869    }
2870
2871    /// Listen for state changes to the underlying connection.
2872    ///
2873    /// This indicates when the connection is open and ready to receive requests
2874    /// through [`State::Open`], or if it's closed and requests will be queued
2875    /// through [`State::Closed`].
2876    ///
2877    /// Note that if you are connecting through a proxy the reported updates
2878    /// might be volatile. It is always best to send a message over the
2879    /// connection on the server side that once received allows the client to
2880    /// know that it is connected.
2881    ///
2882    /// Dropping the returned handle will cancel the listener.
2883    ///
2884    /// # Examples
2885    ///
2886    /// ```
2887    /// # extern crate yew023 as yew;
2888    /// use yew::prelude::*;
2889    /// use musli_web::web03::prelude::*;
2890    ///
2891    /// enum Msg {
2892    ///     StateChange(ws::State),
2893    /// }
2894    ///
2895    /// #[derive(Properties, PartialEq)]
2896    /// struct Props {
2897    ///     ws: ws::Handle,
2898    /// }
2899    ///
2900    /// struct App {
2901    ///     state: ws::State,
2902    ///     _listen: ws::StateListener,
2903    /// }
2904    ///
2905    /// impl Component for App {
2906    ///     type Message = Msg;
2907    ///     type Properties = Props;
2908    ///
2909    ///     fn create(ctx: &Context<Self>) -> Self {
2910    ///         let link = ctx.link().clone();
2911    ///
2912    ///         let (state, listen) = ctx.props().ws.on_state_change(move |state| {
2913    ///             link.send_message(Msg::StateChange(state));
2914    ///         });
2915    ///
2916    ///         Self {
2917    ///             state,
2918    ///             _listen: listen,
2919    ///         }
2920    ///     }
2921    ///
2922    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2923    ///         match msg {
2924    ///             Msg::StateChange(state) => {
2925    ///                 self.state = state;
2926    ///                 true
2927    ///             }
2928    ///         }
2929    ///     }
2930    ///
2931    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2932    ///         html! {
2933    ///             <div>
2934    ///                 <h1>{"WebSocket Example"}</h1>
2935    ///                 <p>{format!("State: {:?}", self.state)}</p>
2936    ///             </div>
2937    ///         }
2938    ///     }
2939    /// }
2940    pub fn on_state_change(&self, callback: impl Callback<State>) -> (State, StateListener) {
2941        let Some(shared) = self.shared.upgrade() else {
2942            return (
2943                State::Closed,
2944                StateListener {
2945                    index: 0,
2946                    g: Weak::new(),
2947                },
2948            );
2949        };
2950
2951        let (state, index) = {
2952            let index = shared
2953                .g
2954                .state_listeners
2955                .borrow_mut()
2956                .insert(Rc::new(callback));
2957            (shared.state.get(), index)
2958        };
2959
2960        let listener = StateListener {
2961            index,
2962            g: Rc::downgrade(&shared.g),
2963        };
2964
2965        (state, listener)
2966    }
2967}
2968
2969impl<H> Clone for Handle<H>
2970where
2971    H: WebImpl,
2972{
2973    #[inline]
2974    fn clone(&self) -> Self {
2975        Self {
2976            shared: self.shared.clone(),
2977        }
2978    }
2979}
2980
2981/// Construct a default handle that is not connected to a backend.
2982///
2983/// # Examples
2984///
2985/// ```
2986/// use musli_web::web03::prelude::*;
2987///
2988/// let handle = ws::Handle::default();
2989/// ```
2990impl<H> Default for Handle<H>
2991where
2992    H: WebImpl,
2993{
2994    #[inline]
2995    fn default() -> Self {
2996        Self {
2997            shared: Weak::new(),
2998        }
2999    }
3000}
3001
3002impl<H> PartialEq for Handle<H>
3003where
3004    H: WebImpl,
3005{
3006    #[inline]
3007    fn eq(&self, other: &Self) -> bool {
3008        Weak::ptr_eq(&self.shared, &other.shared)
3009    }
3010}
3011
3012impl<H> fmt::Debug for Handle<H>
3013where
3014    H: WebImpl,
3015{
3016    #[inline]
3017    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3018        let mut f = f.debug_struct("Handle");
3019
3020        if let Some(shared) = self.shared.upgrade() {
3021            f.field("connect", &shared.connect);
3022            f.field("state", &shared.state.get());
3023        }
3024
3025        f.finish()
3026    }
3027}
3028
3029/// A channel to a WebSocket server.
3030///
3031/// See [`Handle::channel`] for more details.
3032pub struct Channel<H>
3033where
3034    H: WebImpl,
3035{
3036    handle: Handle<H>,
3037    id: ChannelId,
3038}
3039
3040impl<H> Channel<H>
3041where
3042    H: WebImpl,
3043{
3044    /// Get the connection identifier for this handle.
3045    #[inline]
3046    pub fn id(&self) -> ChannelId {
3047        self.id
3048    }
3049
3050    /// Get a handle for this channel.
3051    ///
3052    /// A handle sheds the channel information and allows for setting up things
3053    /// like broadcast listener.
3054    pub fn handle(&self) -> &Handle<H> {
3055        &self.handle
3056    }
3057
3058    /// Send a request of type `T` over the current channel.
3059    ///
3060    /// Returns a handle for the request.
3061    ///
3062    /// If the handle is dropped, the request is cancelled.
3063    ///
3064    /// # Examples
3065    ///
3066    /// ```
3067    /// # extern crate yew023 as yew;
3068    /// use yew::prelude::*;
3069    /// use musli_web::web03::prelude::*;
3070    ///
3071    /// mod api {
3072    ///     use musli::{Decode, Encode};
3073    ///     use musli_web::api;
3074    ///
3075    ///     #[derive(Encode, Decode)]
3076    ///     pub struct HelloRequest<'de> {
3077    ///         pub message: &'de str,
3078    ///     }
3079    ///
3080    ///     #[derive(Encode, Decode)]
3081    ///     pub struct HelloResponse<'de> {
3082    ///         pub message: &'de str,
3083    ///     }
3084    ///
3085    ///     api::define! {
3086    ///         pub type Hello;
3087    ///
3088    ///         impl Endpoint for Hello {
3089    ///             impl<'de> Request for HelloRequest<'de>;
3090    ///             type Response<'de> = HelloResponse<'de>;
3091    ///         }
3092    ///     }
3093    /// }
3094    ///
3095    /// enum Msg {
3096    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
3097    ///     OnChannel(Result<ws::Channel, ws::Error>),
3098    /// }
3099    ///
3100    /// #[derive(Properties, PartialEq)]
3101    /// struct Props {
3102    ///     ws: ws::Handle,
3103    /// }
3104    ///
3105    /// struct App {
3106    ///     message: String,
3107    ///     _hello: ws::Request,
3108    ///     _channel_open: ws::Request,
3109    ///     channel: ws::Channel,
3110    /// }
3111    ///
3112    /// impl Component for App {
3113    ///     type Message = Msg;
3114    ///     type Properties = Props;
3115    ///
3116    ///     fn create(ctx: &Context<Self>) -> Self {
3117    ///         let link = ctx.link().clone();
3118    ///
3119    ///         let _channel_open = ctx.props().ws
3120    ///             .channel()
3121    ///             .on_open(ctx.link().callback(Msg::OnChannel))
3122    ///             .send();
3123    ///
3124    ///         Self {
3125    ///             message: String::from("No Message :("),
3126    ///             _hello: ws::Request::default(),
3127    ///             _channel_open: _channel_open,
3128    ///             channel: ws::Channel::default(),
3129    ///         }
3130    ///     }
3131    ///
3132    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
3133    ///         match msg {
3134    ///             Msg::OnHello(Err(error)) => {
3135    ///                 tracing::error!("Request error: {:?}", error);
3136    ///                 false
3137    ///             }
3138    ///             Msg::OnHello(Ok(packet)) => {
3139    ///                 if let Ok(response) = packet.decode() {
3140    ///                     self.message = response.message.to_owned();
3141    ///                 }
3142    ///
3143    ///                 true
3144    ///             }
3145    ///             Msg::OnChannel(result) => {
3146    ///                 if let Ok(channel) = result {
3147    ///                     self.channel = channel;
3148    ///                 }
3149    ///
3150    ///                 self._hello = self.channel
3151    ///                     .request()
3152    ///                     .body(api::HelloRequest { message: "Hello!"})
3153    ///                     .on_packet(ctx.link().callback(Msg::OnHello))
3154    ///                     .send();
3155    ///
3156    ///                 true
3157    ///             }
3158    ///         }
3159    ///     }
3160    ///
3161    ///     fn view(&self, ctx: &Context<Self>) -> Html {
3162    ///         html! {
3163    ///             <div>
3164    ///                 <h1>{"WebSocket Example"}</h1>
3165    ///                 <p>{format!("Message: {}", self.message)}</p>
3166    ///             </div>
3167    ///         }
3168    ///     }
3169    /// }
3170    /// ```
3171    pub fn request(&self) -> RequestBuilder<'_, H, EmptyBody, EmptyCallback> {
3172        RequestBuilder {
3173            shared: &self.handle.shared,
3174            channel: (self.id != ChannelId::NONE).then_some(self.id),
3175            body: EmptyBody,
3176            callback: EmptyCallback,
3177        }
3178    }
3179}
3180
3181/// Construct a default connected handle.
3182///
3183/// # Examples
3184///
3185/// ```
3186/// use musli_web::web03::prelude::*;
3187///
3188/// let channel = ws::Channel::default();
3189/// assert_eq!(channel.id(), ws::ChannelId::NONE);
3190/// ```
3191impl<H> Default for Channel<H>
3192where
3193    H: WebImpl,
3194{
3195    #[inline]
3196    fn default() -> Self {
3197        Self {
3198            handle: Handle::default(),
3199            id: ChannelId::NONE,
3200        }
3201    }
3202}
3203
3204impl<H> PartialEq for Channel<H>
3205where
3206    H: WebImpl,
3207{
3208    #[inline]
3209    fn eq(&self, other: &Self) -> bool {
3210        Weak::ptr_eq(&self.handle.shared, &other.handle.shared) && self.id == other.id
3211    }
3212}
3213
3214impl<H> Drop for Channel<H>
3215where
3216    H: WebImpl,
3217{
3218    #[inline]
3219    fn drop(&mut self) {
3220        if let Some(shared) = self.handle.shared.upgrade() {
3221            shared.remove_channel(self.id);
3222        }
3223    }
3224}
3225
3226impl<H> fmt::Debug for Channel<H>
3227where
3228    H: WebImpl,
3229{
3230    #[inline]
3231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3232        let mut f = f.debug_struct("Channel");
3233
3234        if let Some(shared) = self.handle.shared.upgrade() {
3235            f.field("connect", &shared.connect);
3236            f.field("state", &shared.state.get());
3237        }
3238
3239        f.field("id", &self.id);
3240        f.finish()
3241    }
3242}
3243
3244struct Pending<C>
3245where
3246    C: ?Sized,
3247{
3248    id: MessageId,
3249    serial: u32,
3250    callback: C,
3251}
3252
3253impl<C> fmt::Debug for Pending<C> {
3254    #[inline]
3255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3256        f.debug_struct("Pending")
3257            .field("serial", &self.serial)
3258            .field("id", &self.id)
3259            .finish_non_exhaustive()
3260    }
3261}
3262
3263struct ForcePrefix<'a>(&'a str, char);
3264
3265impl fmt::Display for ForcePrefix<'_> {
3266    #[inline]
3267    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3268        let Self(string, prefix) = *self;
3269        prefix.fmt(f)?;
3270        string.trim_start_matches(prefix).fmt(f)?;
3271        Ok(())
3272    }
3273}