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//!
9//! # Reconnecting
10//!
11//! The service reconnects on its own whenever the connection is lost, but
12//! nothing sent over the old connection carries over: pending requests fail
13//! with [`Error::is_connection_lost`], and the server forgets every
14//! [`Channel`] which was opened over it. Anything a page fetched has to be
15//! fetched again once the connection is back.
16//!
17//! The one thing it does not reconnect after is a server which states another
18//! application version than the page, which it reports as
19//! [`State::Incompatible`]. The page is out of date and the usual response is
20//! to reload it, see [`ServiceBuilder::app_version`].
21//!
22//! To tell when that is, every handle exposes a connection generation through
23//! [`Handle::generation`]. It counts how many times the connection has opened
24//! so far, so it starts at `0` and goes up by one each time the connection
25//! reaches [`State::Open`]. Since it never goes back, a component can hold on
26//! to the generation it last fetched for and compare it to a single [`Copy`]
27//! value, rather than tracking whether it has seen the connection close.
28//!
29//! There are two ways to learn that the generation has changed:
30//!
31//! * [`Handle::on_open`] calls a listener with the new generation every time
32//!   the connection opens. This suits a component which holds a [`Handle`]
33//!   and fetches its own data.
34//! * [`Handle::on_state_change`] reports every change of [`State`]. A root
35//!   component which already listens for it can read [`Handle::generation`]
36//!   when it sees [`State::Open`], and pass the value down as a property, so
37//!   that a child refetches when the property changes.
38//!
39//! A [`Channel`] is opened again by itself every time the connection reopens,
40//! and tells about it through the callback set with
41//! [`ChannelBuilder::on_change`], see [`Handle::channel`]. A component which
42//! holds a channel can fetch again when it hears [`ChannelEvent::Opened`]
43//! instead of tracking the generation.
44//!
45//! ## Refetching after a reconnect
46//!
47//! This passes the generation down from the root component:
48//!
49//! ```
50//! # extern crate yew023 as yew;
51//! use yew::prelude::*;
52//! use musli_web::web03::prelude::*;
53//!
54//! #[derive(Properties, PartialEq)]
55//! struct ListProps {
56//!     ws: ws::Handle,
57//!     /// The connection generation, from `ws::Handle::generation`.
58//!     generation: u64,
59//! }
60//!
61//! struct List;
62//!
63//! impl List {
64//!     fn fetch(&mut self, ctx: &Context<Self>) {
65//!         // Send the requests this component shows the result of. Before the
66//!         // connection is open they fail as not connected, and are sent again
67//!         // once the generation changes.
68//!     }
69//! }
70//!
71//! impl Component for List {
72//!     type Message = ();
73//!     type Properties = ListProps;
74//!
75//!     fn create(ctx: &Context<Self>) -> Self {
76//!         let mut this = Self;
77//!         this.fetch(ctx);
78//!         this
79//!     }
80//!
81//!     fn changed(&mut self, ctx: &Context<Self>, old: &ListProps) -> bool {
82//!         if ctx.props().generation != old.generation {
83//!             self.fetch(ctx);
84//!         }
85//!
86//!         true
87//!     }
88//!
89//!     fn view(&self, _: &Context<Self>) -> Html {
90//!         html! {}
91//!     }
92//! }
93//!
94//! enum Msg {
95//!     StateChanged(ws::State),
96//! }
97//!
98//! #[derive(Properties, PartialEq)]
99//! struct AppProps {
100//!     ws: ws::Handle,
101//! }
102//!
103//! struct App {
104//!     generation: u64,
105//!     _state: ws::StateListener,
106//! }
107//!
108//! impl Component for App {
109//!     type Message = Msg;
110//!     type Properties = AppProps;
111//!
112//!     fn create(ctx: &Context<Self>) -> Self {
113//!         let (_, state) = ctx
114//!             .props()
115//!             .ws
116//!             .on_state_change(ctx.link().callback(Msg::StateChanged));
117//!
118//!         Self {
119//!             generation: ctx.props().ws.generation(),
120//!             _state: state,
121//!         }
122//!     }
123//!
124//!     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
125//!         match msg {
126//!             Msg::StateChanged(_) => {
127//!                 let generation = ctx.props().ws.generation();
128//!                 let changed = self.generation != generation;
129//!                 self.generation = generation;
130//!                 changed
131//!             }
132//!         }
133//!     }
134//!
135//!     fn view(&self, ctx: &Context<Self>) -> Html {
136//!         html! {
137//!             <List ws={ctx.props().ws.clone()} generation={self.generation} />
138//!         }
139//!     }
140//! }
141//! ```
142
143use core::cell::{Cell, RefCell};
144use core::future::Future;
145use core::hash::Hash;
146use core::marker::PhantomData;
147use core::mem;
148use core::ops::Deref;
149use core::pin::Pin;
150use core::ptr::NonNull;
151use core::task::{Context, Poll, Waker};
152use core::{any, fmt};
153use std::collections::VecDeque;
154
155use alloc::boxed::Box;
156use alloc::format;
157use alloc::rc::Rc;
158use alloc::rc::Weak;
159use alloc::string::{String, ToString};
160use alloc::vec::Vec;
161
162use std::collections::hash_map::{Entry, HashMap};
163
164use slab::Slab;
165
166use crate::api::{self, ChannelId, DecodeBody, Event, Format, MessageId, Mode};
167use crate::format;
168
169#[cfg(test)]
170mod tests;
171
172const MAX_CAPACITY: usize = 1048576;
173
174/// An empty request body.
175#[non_exhaustive]
176pub struct EmptyBody;
177
178/// An empty callback.
179#[non_exhaustive]
180pub struct EmptyCallback;
181
182trait RequestCallback {
183    fn error(&self, error: Error);
184
185    fn as_request(&self) -> Option<&(dyn Callback<Result<RawPacket, Error>> + 'static)> {
186        None
187    }
188
189    fn as_channel(&self) -> Option<&(dyn Fn(Result<ChannelId, Error>) + 'static)> {
190        None
191    }
192
193    /// The format and mode this is a negotiation for, if it is one.
194    fn as_negotiate(&self) -> Option<(Format, Mode)> {
195        None
196    }
197}
198
199/// The pending callback used for a format negotiation issued by the service
200/// itself.
201struct NegotiateCallback(Format, Mode);
202
203impl RequestCallback for NegotiateCallback {
204    #[inline]
205    fn as_negotiate(&self) -> Option<(Format, Mode)> {
206        Some((self.0, self.1))
207    }
208
209    #[inline]
210    fn error(&self, error: Error) {
211        tracing::debug!("Format negotiation failed: {error}");
212    }
213}
214
215/// Slab of state listeners.
216type StateListeners = Slab<Rc<dyn Callback<State>>>;
217/// Slab of broadcast listeners.
218type Broadcasts = HashMap<MessageId, Slab<Rc<dyn Callback<Result<RawPacket>>>>>;
219/// Queue of recycled buffers.
220type Buffers = VecDeque<Box<BufData>>;
221/// Pending requests.
222type PendingRequests = HashMap<u32, Box<Pending<dyn RequestCallback>>>;
223
224/// Location information for WebSocket implementation.
225#[doc(hidden)]
226pub struct Location {
227    pub(crate) protocol: String,
228    pub(crate) host: String,
229    pub(crate) port: String,
230}
231
232pub(crate) mod sealed_socket {
233    pub trait Sealed {}
234}
235
236pub(crate) trait SocketImpl
237where
238    Self: Sized + self::sealed_socket::Sealed,
239{
240    #[doc(hidden)]
241    type Handles;
242
243    #[doc(hidden)]
244    fn new(url: &str, handles: &Self::Handles) -> Result<Self, Error>;
245
246    /// Send a message in the given [`Mode`].
247    ///
248    /// [`Mode::Binary`] writes a binary frame and [`Mode::Text`] a text frame,
249    /// which is what carries the mode between peers.
250    #[doc(hidden)]
251    fn send(&self, mode: Mode, data: &[u8]) -> Result<(), Error>;
252
253    #[doc(hidden)]
254    fn close(self) -> Result<(), Error>;
255}
256
257pub(crate) mod sealed_window {
258    pub trait Sealed {}
259}
260
261pub(crate) trait WindowImpl
262where
263    Self: Sized + self::sealed_window::Sealed,
264{
265    #[doc(hidden)]
266    type Timeout;
267
268    #[doc(hidden)]
269    type OnBeforeUnload;
270
271    #[doc(hidden)]
272    fn new() -> Result<Self, Error>;
273
274    #[doc(hidden)]
275    fn location(&self) -> Result<Location, Error>;
276
277    #[doc(hidden)]
278    fn set_timeout(
279        &self,
280        millis: u32,
281        callback: impl Fn() + 'static,
282    ) -> Result<Self::Timeout, Error>;
283
284    #[doc(hidden)]
285    fn onbeforeunload(&self, callback: impl Fn() + 'static) -> Result<Self::OnBeforeUnload, Error>;
286}
287
288pub(crate) mod sealed_web {
289    pub trait Sealed {}
290}
291
292/// Central trait for web integration.
293///
294/// Since web integration is currently unstable, this requires multiple
295/// different implementations, each time an ecosystem breaking change is
296/// released.
297///
298/// The crate in focus here is `web-sys`, and the corresponding modules provide
299/// integrations:
300///
301/// * [web03] for `web-sys` `0.3.x`.
302///
303/// [web03]: crate::web03
304pub trait WebImpl
305where
306    Self: 'static + Copy + Sized + self::sealed_web::Sealed,
307{
308    #[doc(hidden)]
309    #[allow(private_bounds)]
310    type Window: WindowImpl;
311
312    #[doc(hidden)]
313    type Handles;
314
315    #[doc(hidden)]
316    #[allow(private_bounds)]
317    type Socket: SocketImpl<Handles = Self::Handles>;
318
319    #[doc(hidden)]
320    #[allow(private_interfaces)]
321    fn handles(shared: &Weak<Shared<Self>>) -> Self::Handles;
322
323    #[doc(hidden)]
324    fn random(range: u32) -> u32;
325}
326
327/// Construct a new [`ServiceBuilder`] associated with the given [`Connect`]
328/// strategy.
329pub fn connect<H>(connect: Connect) -> ServiceBuilder<H, EmptyCallback>
330where
331    H: WebImpl,
332{
333    ServiceBuilder {
334        connect,
335        on_error: EmptyCallback,
336        close_before_unload: false,
337        format: Format::DEFAULT,
338        mode: Mode::DEFAULT,
339        app: 0,
340        _marker: PhantomData,
341    }
342}
343
344/// The state of the connection.
345///
346/// A listener for state changes can be set up through for example
347/// [`Handle::on_state_change`].
348#[derive(Debug, PartialEq, Eq, Clone, Copy)]
349#[non_exhaustive]
350pub enum State {
351    /// The connection is open.
352    Open,
353    /// The connection is closed.
354    Closed,
355    /// The server states an application version other than the one this
356    /// client was built with, see [`ServiceBuilder::app_version`].
357    ///
358    /// The connection is closed and the service stops reconnecting, since
359    /// connecting again reaches the same server. The page is out of date, so
360    /// the usual thing to do is to ask the user to reload it, or to reload it
361    /// outright. [`Service::open`] tries again, which is only worth doing if
362    /// the server might have changed back.
363    Incompatible {
364        /// The application version the server states.
365        server: u32,
366        /// The application version this client states.
367        client: u32,
368    },
369}
370
371impl State {
372    /// Check if the state is open.
373    pub fn is_open(&self) -> bool {
374        matches!(self, Self::Open)
375    }
376
377    /// Check if the connection was refused because the server states another
378    /// application version, see [`State::Incompatible`].
379    ///
380    /// # Examples
381    ///
382    /// ```
383    /// use musli_web::web::State;
384    ///
385    /// assert!(State::Incompatible { server: 2, client: 1 }.is_incompatible());
386    /// assert!(!State::Closed.is_incompatible());
387    /// ```
388    pub fn is_incompatible(&self) -> bool {
389        matches!(self, Self::Incompatible { .. })
390    }
391}
392
393/// Error type for the WebSocket service.
394///
395/// Errors are delivered to request, channel and broadcast callbacks, and to
396/// the connection-wide handler set with [`ServiceBuilder::on_error`]. Use the
397/// accessors below to tell what failed instead of matching on the text
398/// produced by [`Display`], which is meant for humans and may change:
399///
400/// * [`is_not_connected`] - the request was never sent, since there was no
401///   open connection or channel to send it over. It is safe to send it again
402///   once the connection is open.
403/// * [`is_connection_lost`] - the request was sent, or about to be, but the
404///   connection closed before a response arrived. The server may or may not
405///   have handled it.
406/// * [`is_cancelled`] - the request was replaced by another one before it was
407///   answered.
408/// * [`as_server_error`] - the server answered with an error, such as one
409///   returned by its handler. If the handler failed with a typed error,
410///   [`server_error`] decodes it.
411/// * [`is_decode`] - something received could not be decoded, such as a
412///   response which does not match the expected type.
413///
414/// Anything else, such as a failure in the browser APIs, only carries a
415/// message.
416///
417/// # Examples
418///
419/// ```
420/// use musli_web::web::Error;
421///
422/// fn describe(error: &Error) -> String {
423///     if error.is_not_connected() {
424///         String::from("Not connected, try again later")
425///     } else if error.is_connection_lost() {
426///         String::from("Connection lost, the request may not have been handled")
427///     } else if let Some(message) = error.as_server_error() {
428///         format!("The server said: {message}")
429///     } else {
430///         error.to_string()
431///     }
432/// }
433///
434/// let error = Error::message("Something else");
435/// assert_eq!(describe(&error), "Something else");
436/// ```
437///
438/// [`Display`]: core::fmt::Display
439/// [`is_not_connected`]: Self::is_not_connected
440/// [`is_connection_lost`]: Self::is_connection_lost
441/// [`is_cancelled`]: Self::is_cancelled
442/// [`as_server_error`]: Self::as_server_error
443/// [`server_error`]: Self::server_error
444/// [`is_decode`]: Self::is_decode
445#[derive(Debug)]
446pub struct Error {
447    kind: ErrorKind,
448}
449
450impl Error {
451    #[inline]
452    fn new(kind: ErrorKind) -> Self {
453        Self { kind }
454    }
455
456    /// Check if the error is caused by an empty packet.
457    ///
458    /// An empty packet is also a [decode error](Self::is_decode).
459    ///
460    /// # Examples
461    ///
462    /// ```
463    /// use musli_web::web::{Error, RawPacket};
464    ///
465    /// let packet = RawPacket::empty();
466    /// let e = packet.decode::<u32>().unwrap_err();
467    ///
468    /// assert!(e.is_empty_packet());
469    /// assert!(e.is_decode());
470    /// ```
471    #[inline]
472    pub fn is_empty_packet(&self) -> bool {
473        matches!(self.kind, ErrorKind::EmptyPacket)
474    }
475
476    /// Check if the request was never sent, since there was no open
477    /// connection or channel to send it over.
478    ///
479    /// This is the error a request or channel gets when it is sent before the
480    /// connection is [open](State::Open), after the [`Service`] has been
481    /// dropped, or over a [`Channel`] which is not open. Since the server never
482    /// saw the request, it is safe to send it again once the connection is
483    /// open, see [`Handle::on_state_change`].
484    ///
485    /// # Examples
486    ///
487    /// ```
488    /// use musli_web::web::Error;
489    ///
490    /// let error = Error::message("Something else");
491    /// assert!(!error.is_not_connected());
492    /// ```
493    #[inline]
494    pub fn is_not_connected(&self) -> bool {
495        matches!(self.kind, ErrorKind::NotConnected(..))
496    }
497
498    /// Check if the connection closed before a response to the request
499    /// arrived.
500    ///
501    /// Unlike [`is_not_connected`], the request was sent, or was being sent,
502    /// so the server may or may not have handled it. This is the error every
503    /// pending request gets when the connection closes or when the
504    /// [`Service`] is dropped.
505    ///
506    /// [`is_not_connected`]: Self::is_not_connected
507    #[inline]
508    pub fn is_connection_lost(&self) -> bool {
509        matches!(self.kind, ErrorKind::ConnectionLost(..))
510    }
511
512    /// Check if the request was cancelled before it was answered, since
513    /// another request took its place.
514    #[inline]
515    pub fn is_cancelled(&self) -> bool {
516        matches!(self.kind, ErrorKind::Cancelled)
517    }
518
519    /// Check if the error is a server error, and if so return the message
520    /// reported by the server.
521    ///
522    /// Server errors are produced by a [`Handler`] which returns an error or
523    /// which does not support the request or broadcast being made. The message
524    /// is returned as the server sent it, without the `Server error: ` prefix
525    /// that [`Display`] adds.
526    ///
527    /// [`Display`]: core::fmt::Display
528    /// [`Handler`]: <https://docs.rs/musli-web/latest/musli_web/ws/trait.Handler.html>
529    ///
530    /// This is the message of a [typed error](Self::server_error) too.
531    #[inline]
532    pub fn as_server_error(&self) -> Option<&str> {
533        match &self.kind {
534            ErrorKind::Server(error) => Some(&error.message),
535            _ => None,
536        }
537    }
538
539    /// Decode the typed error the server answered with.
540    ///
541    /// A handler which fails with a `ws::TypedError<E>` sends `E` encoded in
542    /// the body format of the connection, see [Errors]. This decodes it back
543    /// as `T`, which should be the same type as `E` or one which is
544    /// compatible with it, typically from an API crate shared with the server.
545    ///
546    /// Returns `Ok(None)` if this is not a server error, or if it is one which
547    /// carries no typed error, such as a handler error which is plain text or
548    /// an error the server produced on its own for a request it does not
549    /// support. Those still have a message, see [`as_server_error`].
550    ///
551    /// # Errors
552    ///
553    /// Errors if the typed error does not decode as `T`. The returned error is
554    /// a [decode error](Self::is_decode).
555    ///
556    /// # Examples
557    ///
558    /// ```
559    /// use musli::{Decode, Encode};
560    /// use musli_web::web::Error;
561    ///
562    /// #[derive(Debug, PartialEq, Encode, Decode)]
563    /// enum ServerError {
564    ///     NotFound,
565    ///     Forbidden,
566    /// }
567    ///
568    /// fn describe(error: &Error) -> String {
569    ///     match error.server_error::<ServerError>() {
570    ///         Ok(Some(ServerError::NotFound)) => String::from("No such thing"),
571    ///         Ok(Some(ServerError::Forbidden)) => String::from("Not allowed"),
572    ///         // NB: Not a typed error, or not one we understand.
573    ///         Ok(None) | Err(..) => error.to_string(),
574    ///     }
575    /// }
576    ///
577    /// let error = Error::message("Something else");
578    /// assert_eq!(error.server_error::<ServerError>().unwrap(), None);
579    /// assert_eq!(describe(&error), "Something else");
580    /// ```
581    ///
582    /// [Errors]: <https://docs.rs/musli-web/latest/musli_web/ws/index.html#errors>
583    /// [`as_server_error`]: Self::as_server_error
584    pub fn server_error<'de, T>(&'de self) -> Result<Option<T>>
585    where
586        T: DecodeBody<'de>,
587    {
588        let ErrorKind::Server(error) = &self.kind else {
589            return Ok(None);
590        };
591
592        let Some((format, payload)) = &error.payload else {
593            return Ok(None);
594        };
595
596        let value = format
597            .decode(payload, &mut 0)
598            .map_err(Error::decode_error_message)?;
599
600        Ok(Some(value))
601    }
602
603    /// Check if the error is caused by something received which could not be
604    /// decoded.
605    ///
606    /// This covers a response or broadcast whose body does not decode as the
607    /// requested type, an [empty packet](Self::is_empty_packet), a frame from
608    /// the server whose header, error message or format could not be decoded,
609    /// and a [typed error](Self::server_error) which does not decode as the
610    /// requested type.
611    ///
612    /// # Examples
613    ///
614    /// ```
615    /// use musli_web::web::RawPacket;
616    ///
617    /// let packet = RawPacket::empty();
618    /// let e = packet.decode::<u32>().unwrap_err();
619    ///
620    /// assert!(e.is_decode());
621    /// ```
622    #[inline]
623    pub fn is_decode(&self) -> bool {
624        matches!(
625            self.kind,
626            ErrorKind::EmptyPacket
627                | ErrorKind::UnknownFormat(..)
628                | ErrorKind::DecodeResponseHeader(..)
629                | ErrorKind::DecodeErrorMessage(..)
630                | ErrorKind::DecodePacket(..)
631        )
632    }
633
634    /// Format a WebSocket error consisting of a message.
635    ///
636    /// None of the accessors on [`Error`] match an error constructed this way.
637    #[inline]
638    pub fn message(message: impl fmt::Display) -> Self {
639        Self::new(ErrorKind::Message(message.to_string()))
640    }
641
642    #[inline]
643    fn server(error: ServerError) -> Self {
644        Self::new(ErrorKind::Server(error))
645    }
646
647    #[inline]
648    pub(crate) fn decode_response_header(error: format::Error) -> Self {
649        Self::new(ErrorKind::DecodeResponseHeader(error))
650    }
651
652    #[inline]
653    pub(crate) fn decode_error_message(error: format::Error) -> Self {
654        Self::new(ErrorKind::DecodeErrorMessage(error))
655    }
656
657    #[inline]
658    pub(crate) fn decode_packet(error: format::Error) -> Self {
659        Self::new(ErrorKind::DecodePacket(error))
660    }
661
662    #[inline]
663    pub(crate) fn encoding_header(error: format::Error) -> Self {
664        Self::new(ErrorKind::EncodingHeader(error))
665    }
666
667    #[inline]
668    pub(crate) fn encoding_body(error: format::Error) -> Self {
669        Self::new(ErrorKind::EncodingBody(error))
670    }
671}
672
673#[derive(Debug)]
674enum ErrorKind {
675    EmptyPacket,
676    /// The request was never sent. Carries the text to display.
677    NotConnected(&'static str),
678    /// The connection closed while the request was pending. Carries the text
679    /// to display.
680    ConnectionLost(&'static str),
681    Cancelled,
682    Message(String),
683    Server(ServerError),
684    UnknownFormat(u8),
685    DecodeResponseHeader(format::Error),
686    DecodeErrorMessage(format::Error),
687    DecodePacket(format::Error),
688    EncodingHeader(format::Error),
689    EncodingBody(format::Error),
690}
691
692impl fmt::Display for Error {
693    #[inline]
694    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
695        match &self.kind {
696            ErrorKind::EmptyPacket => write!(f, "Packet is empty"),
697            ErrorKind::NotConnected(message) => write!(f, "{message}"),
698            ErrorKind::ConnectionLost(message) => write!(f, "{message}"),
699            ErrorKind::Cancelled => write!(f, "Request cancelled"),
700            ErrorKind::Message(message) => write!(f, "{message}"),
701            ErrorKind::Server(error) => write!(f, "Server error: {}", error.message),
702            ErrorKind::UnknownFormat(format) => write!(
703                f,
704                "Server used unknown format id {format} for a message body"
705            ),
706            ErrorKind::DecodeResponseHeader(..) => {
707                write!(f, "Encoding error when decoding response header")
708            }
709            ErrorKind::DecodeErrorMessage(..) => {
710                write!(f, "Encoding error when decoding error response")
711            }
712            ErrorKind::DecodePacket(..) => write!(f, "Encoding error when decoding packet"),
713            ErrorKind::EncodingHeader(..) => write!(f, "Encoding error when encoding header"),
714            ErrorKind::EncodingBody(..) => write!(f, "Encoding error when encoding body"),
715        }
716    }
717}
718
719impl core::error::Error for Error {
720    #[inline]
721    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
722        match &self.kind {
723            ErrorKind::DecodeResponseHeader(error) => Some(error),
724            ErrorKind::DecodeErrorMessage(error) => Some(error),
725            ErrorKind::DecodePacket(error) => Some(error),
726            ErrorKind::EncodingHeader(error) => Some(error),
727            ErrorKind::EncodingBody(error) => Some(error),
728            _ => None,
729        }
730    }
731}
732
733#[cfg(feature = "wasm_bindgen02")]
734impl From<wasm_bindgen02::JsValue> for Error {
735    #[inline]
736    fn from(error: wasm_bindgen02::JsValue) -> Self {
737        Self::new(ErrorKind::Message(format!("{error:?}")))
738    }
739}
740
741/// An error response from the server, see [error
742/// responses](crate::api#error-responses).
743#[derive(Debug, Clone)]
744struct ServerError {
745    /// The human readable message.
746    message: String,
747    /// The typed payload, and the format it is encoded with.
748    payload: Option<(Format, Box<[u8]>)>,
749}
750
751impl ServerError {
752    /// A server error without a payload.
753    #[inline]
754    fn message(message: &str) -> Self {
755        Self {
756            message: String::from(message),
757            payload: None,
758        }
759    }
760}
761
762type Result<T, E = Error> = core::result::Result<T, E>;
763
764const INITIAL_TIMEOUT: u32 = 250;
765const MAX_TIMEOUT: u32 = 4000;
766
767/// How to connect to the WebSocket.
768#[derive(Debug)]
769enum ConnectKind {
770    Location { path: String },
771    Url { url: String },
772}
773
774/// A specification for how to connect a WebSocket.
775pub struct Connect {
776    kind: ConnectKind,
777}
778
779impl Connect {
780    /// Connect to the same location with a custom path.
781    ///
782    /// Note that any number of `/` prefixes are ignored, the canonical
783    /// representation always ignores them and the path is relative to the
784    /// current location.
785    #[inline]
786    pub fn location(path: impl AsRef<str>) -> Self {
787        Self {
788            kind: ConnectKind::Location {
789                path: String::from(path.as_ref()),
790            },
791        }
792    }
793
794    /// Connect to the specified URL.
795    #[inline]
796    pub fn url(url: String) -> Self {
797        Self {
798            kind: ConnectKind::Url { url },
799        }
800    }
801}
802
803impl fmt::Debug for Connect {
804    #[inline]
805    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806        self.kind.fmt(f)
807    }
808}
809
810/// Generic but shared fields which do not depend on specialization over `H`.
811struct Generic {
812    state_listeners: RefCell<StateListeners>,
813    /// The number of times the connection has opened, see
814    /// [`Handle::generation`].
815    generation: Cell<u64>,
816    requests: RefCell<PendingRequests>,
817    broadcasts: RefCell<Broadcasts>,
818    buffers: RefCell<Buffers>,
819}
820
821/// Shared implementation details for WebSocket implementations.
822pub(crate) struct Shared<H>
823where
824    H: WebImpl,
825{
826    connect: Connect,
827    state: Cell<State>,
828    should_be: Cell<State>,
829    connecting: Cell<bool>,
830    /// The format in effect, as agreed by the [negotiation protocol].
831    ///
832    /// [negotiation protocol]: crate::api#negotiating-the-format
833    format: Cell<Format>,
834    /// The format the user asked for, re-negotiated on every reconnect.
835    requested: Format,
836    /// The mode in effect, as decided by the frame the negotiation was answered
837    /// in.
838    mode: Cell<Mode>,
839    /// The mode the user asked for, re-negotiated on every reconnect.
840    requested_mode: Mode,
841    /// The application version this client states, or zero for none.
842    app: u32,
843    handle: Handle<H>,
844    pub(crate) on_error: Box<dyn Callback<Error>>,
845    window: H::Window,
846    handles: H::Handles,
847    serial: Cell<u32>,
848    defer_broadcasts: RefCell<VecDeque<Weak<dyn Callback<Result<RawPacket>>>>>,
849    defer_state_listeners: RefCell<VecDeque<Weak<dyn Callback<State>>>>,
850    pub(crate) socket: RefCell<Option<H::Socket>>,
851    output: RefCell<Vec<u8>>,
852    current_timeout: Cell<u32>,
853    reconnect_timeout: RefCell<Option<<H::Window as WindowImpl>::Timeout>>,
854    _window_onbeforeunload: Option<<H::Window as WindowImpl>::OnBeforeUnload>,
855    g: Rc<Generic>,
856}
857
858impl<H> Drop for Shared<H>
859where
860    H: WebImpl,
861{
862    fn drop(&mut self) {
863        if let Some(s) = self.socket.take() {
864            tracing::debug!("Closing connection during drop");
865
866            if let Err(error) = s.close() {
867                self.on_error.call(error);
868            }
869        }
870
871        // We don't need to worry about mutable borrows here, since we only have
872        // weak references to Shared and by virtue of this being dropped they
873        // are all invalid.
874        let state_listeners = mem::take(&mut *self.g.state_listeners.borrow_mut());
875
876        // NB: Listeners are called before the requests are taken, since a
877        // listener can cancel a request of its own, such as a channel which
878        // was being opened.
879        for (_, listener) in state_listeners {
880            listener.call(State::Closed);
881        }
882
883        let requests = mem::take(&mut *self.g.requests.borrow_mut());
884
885        for (_, p) in requests {
886            p.callback.error(Error::new(ErrorKind::ConnectionLost(
887                "Websocket service closed",
888            )));
889        }
890    }
891}
892
893/// Builder of a service.
894pub struct ServiceBuilder<H, E>
895where
896    H: WebImpl,
897{
898    connect: Connect,
899    on_error: E,
900    close_before_unload: bool,
901    format: Format,
902    mode: Mode,
903    app: u32,
904    _marker: PhantomData<H>,
905}
906
907impl<H, E> ServiceBuilder<H, E>
908where
909    H: WebImpl,
910    E: Callback<Error>,
911{
912    /// Set the error handler to use for the service.
913    pub fn on_error<U>(self, on_error: U) -> ServiceBuilder<H, U>
914    where
915        U: Callback<Error>,
916    {
917        ServiceBuilder {
918            connect: self.connect,
919            on_error,
920            close_before_unload: self.close_before_unload,
921            format: self.format,
922            mode: self.mode,
923            app: self.app,
924            _marker: self._marker,
925        }
926    }
927
928    /// Set the [`Format`] to use for message bodies.
929    ///
930    /// The format is negotiated with the server once the connection is
931    /// established, see the [negotiation protocol]. If the server does not
932    /// support it the error is reported through [`ServiceBuilder::on_error`]
933    /// and the connection falls back to [`Format::DEFAULT`], which can be
934    /// observed through [`Handle::format`].
935    ///
936    /// Defaults to [`Format::DEFAULT`].
937    ///
938    /// [negotiation protocol]: crate::api#negotiating-the-format
939    #[inline]
940    pub fn format(mut self, format: Format) -> ServiceBuilder<H, E> {
941        self.format = format;
942        self
943    }
944
945    /// Set the [`Mode`] the socket should run in.
946    ///
947    /// [`Mode::Text`] makes every frame human readable, so the traffic can be
948    /// read straight out of the browser's network inspector. It requires a
949    /// [`Format`] which is human readable too, so it is normally combined with
950    /// [`Format::Json`]:
951    ///
952    /// ```
953    /// use musli_web::api::{Format, Mode};
954    ///
955    /// assert!(Mode::Text.accepts(Format::Json));
956    /// ```
957    ///
958    /// Like the format, the mode is settled with the server once the connection
959    /// is established, see the [negotiation protocol]. A server which cannot
960    /// carry the requested format in the requested mode reports the error
961    /// through [`ServiceBuilder::on_error`] and the connection falls back to
962    /// [`Mode::DEFAULT`], which can be observed through [`Handle::mode`].
963    ///
964    /// Defaults to [`Mode::DEFAULT`].
965    ///
966    /// [negotiation protocol]: crate::api#negotiating-the-format
967    #[inline]
968    pub fn mode(mut self, mode: Mode) -> ServiceBuilder<H, E> {
969        self.mode = mode;
970        self
971    }
972
973    /// State the version of the application's API this client was built
974    /// with.
975    ///
976    /// This is a version of *your* protocol, the requests and broadcasts
977    /// defined with [`api::define!`], as opposed to [`api::VERSION`] which is
978    /// the version of the envelope this crate puts around them. Give it the
979    /// same constant the server passes to `ws::Connect::app_version`, from a
980    /// crate both of them depend on, and bump it whenever the API changes in a
981    /// way an older page cannot cope with.
982    ///
983    /// When the connection is established the server states its version, and
984    /// if it is not this one the service reports [`State::Incompatible`]
985    /// instead of [`State::Open`], closes the connection and stops
986    /// reconnecting. That is how a page which was loaded before the server was
987    /// upgraded learns that it has to reload.
988    ///
989    /// Zero, which is the default, states no version. The check only applies
990    /// when both peers state one, so a client or a server which does not opt
991    /// in behaves exactly as if this did not exist. See [application
992    /// versions].
993    ///
994    /// [`api::define!`]: crate::api::define
995    /// [application versions]: crate::api#application-versions
996    ///
997    /// # Examples
998    ///
999    /// Reloading the page once the server says it is out of date:
1000    ///
1001    /// ```no_run
1002    /// use musli_web::web03::prelude::*;
1003    ///
1004    /// /// Shared with the server, bumped whenever the API changes.
1005    /// const APP_VERSION: u32 = 7;
1006    ///
1007    /// let service = ws::connect(ws::Connect::location("ws"))
1008    ///     .app_version(APP_VERSION)
1009    ///     .build();
1010    ///
1011    /// // Keep the listener for as long as the page should reload itself.
1012    /// let (_, listener) = service.handle().on_state_change(|state: ws::State| {
1013    ///     // Carries both versions, as `State::Incompatible { server, client }`.
1014    ///     if state.is_incompatible() {
1015    ///         reload_page();
1016    ///     }
1017    /// });
1018    ///
1019    /// /// With `web-sys`, `window().location().reload()`.
1020    /// fn reload_page() {
1021    ///     # todo!()
1022    /// }
1023    /// # drop(listener);
1024    /// ```
1025    #[inline]
1026    pub fn app_version(mut self, version: u32) -> Self {
1027        self.app = version;
1028        self
1029    }
1030
1031    /// Install an event handler which will try to close the WebSocket
1032    /// connection on page unload.
1033    ///
1034    /// This is not strictly necessary, but some browsers like Firefox might be
1035    /// slow to recycle the connection unless it has been explicitly closed.
1036    #[inline]
1037    pub fn close_before_unload(mut self) -> Self {
1038        self.close_before_unload = true;
1039        self
1040    }
1041
1042    /// Build a new service and open it.
1043    ///
1044    /// In order to close or open the service again, see [`Service::close`] and
1045    /// [`Service::open`].
1046    pub fn build(self) -> Service<H> {
1047        let window = match H::Window::new() {
1048            Ok(window) => window,
1049            Err(error) => {
1050                panic!("{error}")
1051            }
1052        };
1053
1054        let shared = Rc::<Shared<H>>::new_cyclic(move |shared| {
1055            let window_onbeforeunload = if self.close_before_unload {
1056                let shared = shared.clone();
1057
1058                let result = window.onbeforeunload(move || {
1059                    tracing::debug!("Trying to close WebSocket connection on page unload");
1060
1061                    if let Some(shared) = shared.upgrade() {
1062                        shared.close();
1063                    }
1064                });
1065
1066                match result {
1067                    Ok(onbeforeunload) => Some(onbeforeunload),
1068                    Err(error) => {
1069                        self.on_error.call(Error::message(format_args!(
1070                            "Failed to set onbeforeunload: {error}"
1071                        )));
1072                        None
1073                    }
1074                }
1075            } else {
1076                None
1077            };
1078
1079            Shared {
1080                connect: self.connect,
1081                state: Cell::new(State::Closed),
1082                should_be: Cell::new(State::Closed),
1083                connecting: Cell::new(false),
1084                format: Cell::new(self.format),
1085                requested: self.format,
1086                mode: Cell::new(self.mode),
1087                requested_mode: self.mode,
1088                app: self.app,
1089                handle: Handle {
1090                    shared: shared.clone(),
1091                },
1092                on_error: Box::new(self.on_error),
1093                window,
1094                handles: H::handles(shared),
1095                serial: Cell::new(0),
1096                defer_broadcasts: RefCell::new(VecDeque::new()),
1097                defer_state_listeners: RefCell::new(VecDeque::new()),
1098                socket: RefCell::new(None),
1099                output: RefCell::new(Vec::new()),
1100                current_timeout: Cell::new(INITIAL_TIMEOUT),
1101                reconnect_timeout: RefCell::new(None),
1102                _window_onbeforeunload: window_onbeforeunload,
1103                g: Rc::new(Generic {
1104                    state_listeners: RefCell::new(Slab::new()),
1105                    generation: Cell::new(0),
1106                    broadcasts: RefCell::new(HashMap::new()),
1107                    requests: RefCell::new(PendingRequests::new()),
1108                    buffers: RefCell::new(VecDeque::new()),
1109                }),
1110            }
1111        });
1112
1113        let service = Service { shared };
1114        service.open();
1115        service
1116    }
1117}
1118
1119/// The service handle.
1120///
1121/// Once dropped this will cause the service to be disconnected and all requests
1122/// to be cancelled.
1123pub struct Service<H>
1124where
1125    H: WebImpl,
1126{
1127    shared: Rc<Shared<H>>,
1128}
1129
1130impl<H> Service<H>
1131where
1132    H: WebImpl,
1133{
1134    /// Attempt to establish a WebSocket connection.
1135    #[deprecated(since = "0.3.0", note = "Use `open` instead")]
1136    pub fn connect(&self) {
1137        self.shared.open()
1138    }
1139
1140    /// Open the WebSocket connection.
1141    ///
1142    /// Calling this method indicates that the connection should stay open, and
1143    /// the implementation will attempt to reconnect until [`Service::close`] is
1144    /// called.
1145    pub fn open(&self) {
1146        self.shared.open()
1147    }
1148
1149    /// Close the WebSocket connection.
1150    ///
1151    /// This is not strictly necessary, but some browsers like Firefox might be
1152    /// slow to recycle the connection unless it has been explicitly closed.
1153    ///
1154    /// It is generally recommended that you call this when `beforeunload` on
1155    /// window is fired.
1156    pub fn close(&self) {
1157        self.shared.close();
1158    }
1159
1160    /// Return the handle to the service.
1161    ///
1162    /// A [`Handle`] instances does not force the underlying WebSocket to stay
1163    /// connected, and is invalidated when [`Service`] is destructed.
1164    pub fn handle(&self) -> &Handle<H> {
1165        &self.shared.handle
1166    }
1167}
1168
1169impl<H> Clone for Service<H>
1170where
1171    H: WebImpl,
1172{
1173    #[inline]
1174    fn clone(&self) -> Self {
1175        Self {
1176            shared: self.shared.clone(),
1177        }
1178    }
1179}
1180
1181impl<H> Shared<H>
1182where
1183    H: WebImpl,
1184{
1185    /// Send a client message.
1186    fn send_client_request<T>(&self, serial: u32, channel: ChannelId, body: &T) -> Result<()>
1187    where
1188        T: api::Request,
1189    {
1190        let Some(ref socket) = *self.socket.borrow() else {
1191            return Err(Error::new(ErrorKind::NotConnected(
1192                "Socket is not connected",
1193            )));
1194        };
1195
1196        let format = self.format.get();
1197        let mode = self.mode.get();
1198
1199        let header = api::RequestHeader {
1200            version: api::VERSION,
1201            serial,
1202            id: <T::Endpoint as api::Endpoint>::ID.get(),
1203            format: format.to_u8(),
1204            channel,
1205            app: 0,
1206        };
1207
1208        let out = &mut *self.output.borrow_mut();
1209
1210        format::encode_envelope(mode, &mut *out, &header).map_err(Error::encoding_header)?;
1211        format
1212            .encode(&mut *out, body)
1213            .map_err(Error::encoding_body)?;
1214
1215        tracing::debug!(
1216            header.serial,
1217            ?header.id,
1218            len = out.len(),
1219            "Sending request"
1220        );
1221
1222        socket.send(mode, out.as_slice())?;
1223
1224        out.clear();
1225        out.shrink_to(MAX_CAPACITY);
1226        Ok(())
1227    }
1228
1229    /// Send a client message.
1230    fn send_connect(&self, serial: u32) -> Result<()> {
1231        let Some(ref socket) = *self.socket.borrow() else {
1232            return Err(Error::new(ErrorKind::NotConnected(
1233                "Socket is not connected",
1234            )));
1235        };
1236
1237        let mode = self.mode.get();
1238
1239        let header = api::RequestHeader {
1240            version: api::VERSION,
1241            serial,
1242            id: MessageId::CONNECT.get(),
1243            // NB: Carries no body.
1244            format: 0,
1245            channel: ChannelId::NONE,
1246            app: 0,
1247        };
1248
1249        let out = &mut *self.output.borrow_mut();
1250
1251        format::encode_envelope(mode, &mut *out, &header).map_err(Error::encoding_header)?;
1252
1253        tracing::debug!(
1254            header.serial,
1255            ?header.id,
1256            len = out.len(),
1257            "Sending request"
1258        );
1259
1260        socket.send(mode, out.as_slice())?;
1261
1262        out.clear();
1263        out.shrink_to(MAX_CAPACITY);
1264        Ok(())
1265    }
1266
1267    /// Ask the server to use the requested format for the rest of the
1268    /// connection.
1269    fn send_negotiate(self: &Rc<Self>) -> Result<()> {
1270        let format = self.requested;
1271        let mode = self.requested_mode;
1272        let serial = self.serial.get();
1273        self.serial.set(serial.wrapping_add(1));
1274
1275        {
1276            let Some(ref socket) = *self.socket.borrow() else {
1277                return Err(Error::new(ErrorKind::NotConnected(
1278                    "Socket is not connected",
1279                )));
1280            };
1281
1282            let header = api::RequestHeader {
1283                version: api::VERSION,
1284                serial,
1285                id: MessageId::NEGOTIATE.get(),
1286                format: format.to_u8(),
1287                // NB: Carries no body.
1288                channel: ChannelId::NONE,
1289                app: self.app,
1290            };
1291
1292            let out = &mut *self.output.borrow_mut();
1293
1294            // NB: The frame this goes out in is what asks for the mode, so the
1295            // envelope has to be spelled the same way.
1296            format::encode_envelope(mode, &mut *out, &header).map_err(Error::encoding_header)?;
1297
1298            tracing::debug!(?format, ?mode, "Requesting format");
1299
1300            socket.send(mode, out.as_slice())?;
1301
1302            out.clear();
1303            out.shrink_to(MAX_CAPACITY);
1304        }
1305
1306        let pending = Pending {
1307            id: MessageId::NEGOTIATE,
1308            serial,
1309            callback: NegotiateCallback(format, mode),
1310        };
1311
1312        let existing = self
1313            .g
1314            .requests
1315            .borrow_mut()
1316            .insert(serial, Box::new(pending));
1317
1318        if let Some(p) = existing {
1319            p.callback.error(Error::new(ErrorKind::Cancelled));
1320        }
1321
1322        Ok(())
1323    }
1324
1325    /// Send a disconnect.
1326    fn remove_channel(&self, channel: ChannelId) {
1327        if let Err(error) = self._send_disconnect(channel) {
1328            self.on_error.call(error);
1329        }
1330    }
1331
1332    fn _send_disconnect(&self, channel: ChannelId) -> Result<()> {
1333        let Some(ref socket) = *self.socket.borrow() else {
1334            return Err(Error::new(ErrorKind::NotConnected(
1335                "Socket is not connected",
1336            )));
1337        };
1338
1339        let mode = self.mode.get();
1340
1341        let header = api::RequestHeader {
1342            version: api::VERSION,
1343            serial: 0,
1344            id: MessageId::DISCONNECT.get(),
1345            // NB: Carries no body.
1346            format: 0,
1347            channel,
1348            app: 0,
1349        };
1350
1351        let out = &mut *self.output.borrow_mut();
1352
1353        format::encode_envelope(mode, &mut *out, &header).map_err(Error::encoding_header)?;
1354
1355        tracing::debug!(
1356            header.serial,
1357            ?header.id,
1358            len = out.len(),
1359            "Sending request"
1360        );
1361
1362        socket.send(mode, out.as_slice())?;
1363
1364        out.clear();
1365        out.shrink_to(MAX_CAPACITY);
1366        Ok(())
1367    }
1368
1369    pub(crate) fn next_buffer(self: &Rc<Self>, needed: usize) -> Box<BufData> {
1370        match self.g.buffers.borrow_mut().pop_front() {
1371            Some(mut buf) => {
1372                // NB: Recycled buffers are cleared when they are returned, so
1373                // every message starts writing from the beginning.
1374                debug_assert!(buf.data.is_empty());
1375                buf.data.reserve(needed);
1376                buf
1377            }
1378            None => Box::new(BufData::with_capacity(Rc::downgrade(&self.g), needed)),
1379        }
1380    }
1381
1382    /// Handle a text frame.
1383    pub(crate) fn text_message(self: &Rc<Self>, text: &str) -> Result<()> {
1384        let bytes = text.as_bytes();
1385        let mut buf = self.next_buffer(bytes.len());
1386        buf.data.extend_from_slice(bytes);
1387        self.message(Mode::Text, buf)
1388    }
1389
1390    /// Resolve the format a message body is encoded with from its envelope.
1391    fn body_format(header: &api::ResponseHeader) -> Result<Format> {
1392        let Some(format) = Format::from_u8(header.format) else {
1393            return Err(Error::new(ErrorKind::UnknownFormat(header.format)));
1394        };
1395
1396        Ok(format)
1397    }
1398
1399    /// Decode the body of an error response, whose `error` header is `id`.
1400    ///
1401    /// An error id which carries no message is reported with `unsupported`.
1402    fn server_error(
1403        id: MessageId,
1404        header: &api::ResponseHeader,
1405        buf: &[u8],
1406        mut at: usize,
1407        unsupported: &str,
1408    ) -> Result<ServerError> {
1409        let typed = match id {
1410            MessageId::ERROR_MESSAGE => false,
1411            MessageId::TYPED_ERROR_MESSAGE => true,
1412            _ => return Ok(ServerError::message(unsupported)),
1413        };
1414
1415        let format = Self::body_format(header)?;
1416
1417        let error: api::ErrorMessage<'_> = format
1418            .decode(buf, &mut at)
1419            .map_err(Error::decode_error_message)?;
1420
1421        // NB: The payload is only decoded once the caller says what type it
1422        // is, see `Error::server_error`.
1423        let payload = if typed {
1424            Some((format, Box::from(buf.get(at..).unwrap_or_default())))
1425        } else {
1426            None
1427        };
1428
1429        Ok(ServerError {
1430            message: String::from(error.message),
1431            payload,
1432        })
1433    }
1434
1435    pub(crate) fn message(self: &Rc<Self>, mode: Mode, buf: Box<BufData>) -> Result<()> {
1436        // Wrap the buffer in a simple shared reference-counted container.
1437        let buf = BufRc::new(buf);
1438        let mut at = 0;
1439
1440        // NB: The frame type is the mode, so a message can always be read
1441        // regardless of what has been agreed on.
1442        let header: api::ResponseHeader = match format::decode_envelope(mode, &buf, &mut at) {
1443            Ok(header) => header,
1444            // NB: The server speaks a protocol this build does not have, so
1445            // there is nothing to be gained by carrying on with the session.
1446            // The connection is dropped rather than negotiated.
1447            Err(error) if error.unsupported_version().is_some() => {
1448                self.on_error.call(Error::decode_response_header(error));
1449                return self.close_and_reconnect();
1450            }
1451            Err(error) => return Err(Error::decode_response_header(error)),
1452        };
1453
1454        if let Some(broadcast) = MessageId::new(header.broadcast) {
1455            tracing::debug!(?header, "Got broadcast");
1456
1457            if broadcast == MessageId::SERVER_HELLO {
1458                // NB: The connection is not reported as open until the format
1459                // has been negotiated, so that server-initiated messages are
1460                // never encoded with a format this client did not agree to.
1461                tracing::debug!("Server hello, negotiating format");
1462                self.send_negotiate()?;
1463
1464                // NB: Checked after negotiating, so that the server hears
1465                // which version this client states and can tell why it goes
1466                // away.
1467                if self.app != 0 && header.app != 0 && header.app != self.app {
1468                    self.incompatible(header.app);
1469                }
1470
1471                return Ok(());
1472            }
1473
1474            if !self.defer_broadcasts(broadcast) {
1475                return Ok(());
1476            };
1477
1478            if let Some(id) = MessageId::new(header.error) {
1479                let error = Self::server_error(id, &header, &buf, at, "Unsupported broadcast")?;
1480
1481                while let Some(callback) = self.defer_broadcasts.borrow_mut().pop_front() {
1482                    if let Some(callback) = callback.upgrade() {
1483                        callback.call(Err(Error::server(error.clone())));
1484                    }
1485                }
1486
1487                return Ok(());
1488            }
1489
1490            let format = Self::body_format(&header)?;
1491
1492            let packet = RawPacket {
1493                buf: Some(buf.clone()),
1494                at: Cell::new(at),
1495                id: broadcast,
1496                format,
1497                channel: header.channel,
1498            };
1499
1500            while let Some(callback) = self.defer_broadcasts.borrow_mut().pop_front() {
1501                if let Some(callback) = callback.upgrade() {
1502                    callback.call(Ok(packet.clone()));
1503                }
1504            }
1505        } else {
1506            tracing::debug!(?header, "Got response");
1507            let p = self.g.requests.borrow_mut().remove(&header.serial);
1508
1509            if let Some(p) = p {
1510                if let Some(id) = MessageId::new(header.error) {
1511                    let error =
1512                        match Self::server_error(id, &header, &buf, at, "Unsupported request") {
1513                            Ok(error) => error,
1514                            // NB: Fail the request rather than leave it waiting
1515                            // for a response which has already arrived.
1516                            Err(error) if p.callback.as_negotiate().is_none() => {
1517                                p.callback.error(error);
1518                                return Ok(());
1519                            }
1520                            Err(error) => return Err(error),
1521                        };
1522
1523                    if let Some((format, requested)) = p.callback.as_negotiate() {
1524                        // NB: The server cannot speak the requested format, or
1525                        // cannot carry it in the requested mode, so fall back to
1526                        // the defaults rather than leaving the connection
1527                        // unusable.
1528                        self.on_error.call(Error::message(format_args!(
1529                            "Server rejected format `{format}` in `{requested}` mode ({}), falling back to `{}`",
1530                            error.message,
1531                            Format::DEFAULT
1532                        )));
1533
1534                        self.format.set(Format::DEFAULT);
1535                        // NB: The frame this arrived in is the mode the server
1536                        // settled on, so there is nothing to guess at.
1537                        self.mode.set(mode);
1538                        self.emit_state_change(State::Open);
1539                        return Ok(());
1540                    }
1541
1542                    p.callback.error(Error::server(error));
1543                    return Ok(());
1544                }
1545
1546                match p.id {
1547                    MessageId::NEGOTIATE => {
1548                        let Some((requested, _)) = p.callback.as_negotiate() else {
1549                            p.callback
1550                                .error(Error::message("Unexpected negotiate response"));
1551                            return Ok(());
1552                        };
1553
1554                        // NB: Trust the format the server echoed back over the
1555                        // one that was asked for, so that a server which
1556                        // downgrades is honored. The mode is read off the frame
1557                        // for the same reason.
1558                        let accepted = Format::from_u8(header.format).unwrap_or(requested);
1559                        tracing::debug!(?accepted, ?mode, "Format negotiated");
1560                        self.format.set(accepted);
1561                        self.mode.set(mode);
1562                        self.emit_state_change(State::Open);
1563                        return Ok(());
1564                    }
1565                    MessageId::CONNECT => {
1566                        let Some(callback) = &p.callback.as_channel() else {
1567                            p.callback
1568                                .error(Error::message("Unexpected channel response"));
1569                            return Ok(());
1570                        };
1571
1572                        callback(Ok(header.channel));
1573                        return Ok(());
1574                    }
1575                    _ => {
1576                        let Some(callback) = p.callback.as_request() else {
1577                            p.callback
1578                                .error(Error::message("Unexpected channel response"));
1579                            return Ok(());
1580                        };
1581
1582                        let format = Self::body_format(&header)?;
1583
1584                        let packet = RawPacket {
1585                            id: p.id,
1586                            buf: Some(buf),
1587                            at: Cell::new(at),
1588                            format,
1589                            channel: header.channel,
1590                        };
1591
1592                        callback.call(Ok(packet));
1593                        return Ok(());
1594                    }
1595                }
1596            }
1597
1598            // NB: This is normal, it simply indicates that the handler has been
1599            // closed.
1600            tracing::trace!(?header.serial, "Got message with unknown serial");
1601        }
1602
1603        Ok(())
1604    }
1605
1606    fn defer_broadcasts(self: &Rc<Self>, kind: MessageId) -> bool {
1607        // Note: We need to defer this, since the outcome of calling
1608        // the broadcast callback might be that the broadcast
1609        // listener is modified, which could require mutable access
1610        // to broadcasts.
1611        let mut defer = self.defer_broadcasts.borrow_mut();
1612
1613        let broadcasts = self.g.broadcasts.borrow();
1614
1615        let Some(broadcasts) = broadcasts.get(&kind) else {
1616            return false;
1617        };
1618
1619        for (_, callback) in broadcasts.iter() {
1620            defer.push_back(Rc::downgrade(callback));
1621        }
1622
1623        !defer.is_empty()
1624    }
1625
1626    pub(crate) fn close_and_reconnect(self: &Rc<Self>) -> Result<(), Error> {
1627        tracing::debug!("Closing and reconnecting");
1628
1629        // We need a weak reference back to shared state to handle the timeout.
1630        let shared = Rc::downgrade(self);
1631
1632        if self.state.get() == State::Closed {
1633            let current_timeout = self.current_timeout.get();
1634
1635            if current_timeout < MAX_TIMEOUT {
1636                let fuzz = H::random(50);
1637
1638                self.current_timeout.set(
1639                    current_timeout
1640                        .saturating_mul(2)
1641                        .saturating_add(fuzz)
1642                        .min(MAX_TIMEOUT),
1643                );
1644            }
1645        } else {
1646            self.current_timeout.set(INITIAL_TIMEOUT);
1647            self.close_once();
1648        }
1649
1650        let timeout = self.current_timeout.get();
1651
1652        tracing::debug!(?timeout, "Setting");
1653
1654        let timeout = self.window.set_timeout(timeout, move || {
1655            if let Some(shared) = shared.upgrade() {
1656                Self::try_once(&shared);
1657            }
1658        })?;
1659
1660        drop(self.reconnect_timeout.borrow_mut().replace(timeout));
1661        self.connecting.set(false);
1662        Ok(())
1663    }
1664
1665    /// Give up on a server which states application version `server`.
1666    ///
1667    /// Connecting again would reach the same server, so this stops
1668    /// reconnecting until [`Service::open`] is called again.
1669    fn incompatible(self: &Rc<Self>, server: u32) {
1670        let client = self.app;
1671        tracing::debug!(server, client, "Incompatible server");
1672
1673        self.should_be.set(State::Closed);
1674
1675        let timeout = self.reconnect_timeout.borrow_mut().take();
1676        drop(timeout);
1677
1678        self.current_timeout.set(INITIAL_TIMEOUT);
1679        self.connecting.set(false);
1680
1681        // NB: The socket goes first, so that a listener which looks at the
1682        // service sees it closed.
1683        if let Some(s) = self.socket.take() {
1684            if let Err(error) = s.close() {
1685                self.on_error.call(error);
1686            }
1687        }
1688
1689        self.close_pending();
1690        self.emit_state_change(State::Incompatible { server, client });
1691    }
1692
1693    /// Fail the pending request with the given serial, if it is still pending.
1694    fn fail_request(&self, serial: u32, error: Error) {
1695        let p = self.g.requests.borrow_mut().remove(&serial);
1696
1697        if let Some(p) = p {
1698            p.callback.error(error);
1699        }
1700    }
1701
1702    /// Close an pending requests with an error, since there is no chance they
1703    /// will be responded to any more.
1704    fn close_pending(self: &Rc<Self>) {
1705        loop {
1706            let Some(serial) = self.g.requests.borrow().keys().next().copied() else {
1707                break;
1708            };
1709
1710            let p = {
1711                let mut requests = self.g.requests.borrow_mut();
1712
1713                let Some(p) = requests.remove(&serial) else {
1714                    break;
1715                };
1716
1717                p
1718            };
1719
1720            p.callback
1721                .error(Error::new(ErrorKind::ConnectionLost("Connection closed")));
1722        }
1723    }
1724
1725    fn emit_state_change(&self, state: State) {
1726        if self.state.get() == state {
1727            return;
1728        }
1729
1730        self.state.set(state);
1731
1732        if state == State::Open {
1733            // NB: Bumped before any listener runs, so that every listener sees
1734            // the generation of the connection that just opened.
1735            let generation = self.g.generation.get().wrapping_add(1);
1736            self.g.generation.set(generation);
1737        }
1738
1739        {
1740            // We need to collect callbacks to avoid the callback recursively
1741            // borrowing state listeners, which it would if it modifies any
1742            // existing state listeners.
1743            let mut defer = self.defer_state_listeners.borrow_mut();
1744
1745            for (_, callback) in self.g.state_listeners.borrow().iter() {
1746                defer.push_back(Rc::downgrade(callback));
1747            }
1748
1749            if defer.is_empty() {
1750                return;
1751            }
1752        }
1753
1754        while let Some(callback) = self.defer_state_listeners.borrow_mut().pop_front() {
1755            if let Some(callback) = callback.upgrade() {
1756                callback.call(state);
1757            }
1758        }
1759    }
1760
1761    #[inline]
1762    fn open(self: &Rc<Self>) {
1763        self.should_be.set(State::Open);
1764        self.try_once();
1765    }
1766
1767    fn close(self: &Rc<Self>) {
1768        self.should_be.set(State::Closed);
1769
1770        // NB: A pending reconnect would otherwise only be stopped by
1771        // `should_be` once it fires, and would keep the timer alive until then.
1772        let timeout = self.reconnect_timeout.borrow_mut().take();
1773        drop(timeout);
1774
1775        // NB: The next `open` starts over rather than inheriting the back-off
1776        // of the connection which was closed on purpose.
1777        self.current_timeout.set(INITIAL_TIMEOUT);
1778        self.close_once();
1779    }
1780
1781    fn try_once(self: &Rc<Self>) {
1782        if self.should_be.get() == State::Open && !self.connecting.get() {
1783            tracing::debug!("Trying to open connection");
1784            self.connect_once();
1785        }
1786    }
1787
1788    fn close_once(self: &Rc<Self>) {
1789        self.connecting.set(false);
1790        self.emit_state_change(State::Closed);
1791
1792        if let Some(s) = self.socket.take() {
1793            tracing::debug!("Closing old socket once");
1794
1795            if let Err(error) = s.close() {
1796                self.on_error.call(error);
1797            }
1798        }
1799
1800        self.close_pending();
1801    }
1802
1803    fn connect_once(self: &Rc<Self>) {
1804        self.connecting.set(true);
1805
1806        // NB: A failed attempt leaves no socket behind whose events could ever
1807        // reset `connecting`, so it has to be reset here or `open` would never
1808        // try again.
1809        if let Err(error) = self.try_connect() {
1810            self.on_error.call(error);
1811            self.should_be.set(State::Closed);
1812            self.connecting.set(false);
1813        }
1814    }
1815
1816    fn try_connect(self: &Rc<Self>) -> Result<()> {
1817        let url = match &self.connect.kind {
1818            ConnectKind::Location { path } => {
1819                let location = match WindowImpl::location(&self.window) {
1820                    Ok(location) => location,
1821                    Err(e) => {
1822                        return Err(Error::message(format_args!("Could not get location: {e}")));
1823                    }
1824                };
1825
1826                let Location {
1827                    protocol,
1828                    host,
1829                    port,
1830                } = location;
1831
1832                let protocol = match protocol.as_str() {
1833                    "https:" => "wss:",
1834                    "http:" => "ws:",
1835                    other => {
1836                        return Err(Error::message(format_args!(
1837                            "Unsupported protocol `{other}` for same host connection"
1838                        )));
1839                    }
1840                };
1841
1842                let path = ForcePrefix(path, '/');
1843                format!("{protocol}//{host}:{port}{path}")
1844            }
1845            ConnectKind::Url { url } => url.clone(),
1846        };
1847
1848        // We explicitly want to close and dispose of the old socket first.
1849        if let Some(s) = self.socket.borrow_mut().take() {
1850            tracing::debug!("Closing old socket");
1851
1852            if let Err(error) = s.close() {
1853                self.on_error.call(error);
1854            }
1855        }
1856
1857        let ws = SocketImpl::new(&url, &self.handles)?;
1858        *self.socket.borrow_mut() = Some(ws);
1859        Ok(())
1860    }
1861}
1862
1863/// Trait governing how callbacks are called.
1864pub trait Callback<I>
1865where
1866    Self: 'static,
1867{
1868    /// Call the callback.
1869    fn call(&self, input: I);
1870}
1871
1872impl<I> Callback<I> for EmptyCallback {
1873    #[inline]
1874    fn call(&self, _: I) {}
1875}
1876
1877impl<F, I> Callback<I> for F
1878where
1879    F: 'static + Fn(I),
1880{
1881    #[inline]
1882    fn call(&self, input: I) {
1883        self(input)
1884    }
1885}
1886
1887/// A builder for a [`Channel`], see [`Handle::channel`].
1888///
1889/// Set the callback to tell about the channel opening and closing with
1890/// [`ChannelBuilder::on_change`], and open the channel with
1891/// [`ChannelBuilder::open`].
1892pub struct ChannelBuilder<'a, H, C>
1893where
1894    H: WebImpl,
1895{
1896    shared: &'a Weak<Shared<H>>,
1897    callback: C,
1898}
1899
1900impl<'a, H, C> ChannelBuilder<'a, H, C>
1901where
1902    H: WebImpl,
1903{
1904    /// Set the callback which is told about the channel opening and closing.
1905    ///
1906    /// The callback is called with:
1907    ///
1908    /// * [`ChannelEvent::Opened`] every time the channel has been opened,
1909    ///   whether for the first time or again after a reconnect. This is the
1910    ///   point at which to send the requests which need the channel.
1911    /// * [`ChannelEvent::Closed`] when an open channel has been lost with the
1912    ///   connection.
1913    /// * [`ChannelEvent::Failed`] when the server could not open the channel.
1914    ///
1915    /// # Examples
1916    ///
1917    /// ```
1918    /// # extern crate yew023 as yew;
1919    /// use yew::prelude::*;
1920    /// use musli_web::web03::prelude::*;
1921    ///
1922    /// mod api {
1923    ///     use musli::{Decode, Encode};
1924    ///     use musli_web::api;
1925    ///
1926    ///     #[derive(Encode, Decode)]
1927    ///     pub struct HelloRequest<'de> {
1928    ///         pub message: &'de str,
1929    ///     }
1930    ///
1931    ///     #[derive(Encode, Decode)]
1932    ///     pub struct HelloResponse<'de> {
1933    ///         pub message: &'de str,
1934    ///     }
1935    ///
1936    ///     api::define! {
1937    ///         pub type Hello;
1938    ///
1939    ///         impl Endpoint for Hello {
1940    ///             impl<'de> Request for HelloRequest<'de>;
1941    ///             type Response<'de> = HelloResponse<'de>;
1942    ///         }
1943    ///     }
1944    /// }
1945    ///
1946    /// enum Msg {
1947    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
1948    ///     Channel(ws::ChannelEvent),
1949    /// }
1950    ///
1951    /// #[derive(Properties, PartialEq)]
1952    /// struct Props {
1953    ///     ws: ws::Handle,
1954    /// }
1955    ///
1956    /// struct App {
1957    ///     message: String,
1958    ///     _hello: ws::Request,
1959    ///     channel: ws::Channel,
1960    /// }
1961    ///
1962    /// impl Component for App {
1963    ///     type Message = Msg;
1964    ///     type Properties = Props;
1965    ///
1966    ///     fn create(ctx: &Context<Self>) -> Self {
1967    ///         let channel = ctx.props().ws
1968    ///             .channel()
1969    ///             .on_change(ctx.link().callback(Msg::Channel))
1970    ///             .open();
1971    ///
1972    ///         Self {
1973    ///             message: String::from("No Message :("),
1974    ///             _hello: ws::Request::new(),
1975    ///             channel,
1976    ///         }
1977    ///     }
1978    ///
1979    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
1980    ///         match msg {
1981    ///             Msg::OnHello(Err(error)) => {
1982    ///                 tracing::error!("Request error: {:?}", error);
1983    ///                 false
1984    ///             }
1985    ///             Msg::OnHello(Ok(packet)) => {
1986    ///                 if let Ok(response) = packet.decode() {
1987    ///                     self.message = response.message.to_owned();
1988    ///                 }
1989    ///
1990    ///                 true
1991    ///             }
1992    ///             Msg::Channel(ws::ChannelEvent::Opened(..)) => {
1993    ///                 self._hello = self.channel
1994    ///                     .request()
1995    ///                     .body(api::HelloRequest { message: "Hello!"})
1996    ///                     .on_packet(ctx.link().callback(Msg::OnHello))
1997    ///                     .send();
1998    ///
1999    ///                 true
2000    ///             }
2001    ///             Msg::Channel(ws::ChannelEvent::Failed(error)) => {
2002    ///                 tracing::error!("Channel error: {error}");
2003    ///                 true
2004    ///             }
2005    ///             Msg::Channel(..) => true,
2006    ///         }
2007    ///     }
2008    ///
2009    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2010    ///         html! {
2011    ///             <div>
2012    ///                 <h1>{"WebSocket Example"}</h1>
2013    ///                 <p>{format!("Message: {}", self.message)}</p>
2014    ///             </div>
2015    ///         }
2016    ///     }
2017    /// }
2018    /// ```
2019    pub fn on_change<U>(self, callback: U) -> ChannelBuilder<'a, H, U>
2020    where
2021        U: Callback<ChannelEvent>,
2022    {
2023        ChannelBuilder {
2024            shared: self.shared,
2025            callback,
2026        }
2027    }
2028}
2029
2030impl<'a, H, C> ChannelBuilder<'a, H, C>
2031where
2032    C: Callback<ChannelEvent>,
2033    H: WebImpl,
2034{
2035    /// Open the channel.
2036    ///
2037    /// The channel is opened straight away if the connection is open, and
2038    /// otherwise as soon as it opens. After that it is opened again every time
2039    /// the connection reopens, until the returned [`Channel`] and every clone
2040    /// of it has been dropped.
2041    pub fn open(self) -> Channel<H> {
2042        let inner = Rc::new(ChannelInner {
2043            handle: Handle {
2044                shared: self.shared.clone(),
2045            },
2046            id: Cell::new(ChannelId::NONE),
2047            generation: Cell::new(0),
2048            on_change: Box::new(self.callback),
2049            queue: RefCell::new(VecDeque::new()),
2050            connect: RefCell::new(Request::new()),
2051            state: RefCell::new(StateListener::new()),
2052        });
2053
2054        let (state, listener) = inner.handle.on_state_change({
2055            // NB: Weak, since the listener is owned by the channel.
2056            let inner = Rc::downgrade(&inner);
2057
2058            move |state: State| {
2059                if let Some(inner) = inner.upgrade() {
2060                    inner.on_state(state);
2061                }
2062            }
2063        });
2064
2065        *inner.state.borrow_mut() = listener;
2066
2067        if state.is_open() {
2068            inner.connect();
2069        }
2070
2071        Channel { inner }
2072    }
2073}
2074
2075/// Ask the server for a new channel over the current connection.
2076///
2077/// The callback is called with the id the server allocated, or with the error
2078/// which prevented it.
2079fn connect_channel<H>(
2080    shared: &Weak<Shared<H>>,
2081    callback: impl Fn(Result<ChannelId, Error>) + 'static,
2082) -> Request
2083where
2084    H: WebImpl,
2085{
2086    struct RequestCallbackImpl<C>(C);
2087
2088    impl<C> RequestCallback for RequestCallbackImpl<C>
2089    where
2090        C: Fn(Result<ChannelId, Error>) + 'static,
2091    {
2092        #[inline]
2093        fn as_channel(&self) -> Option<&(dyn Fn(Result<ChannelId, Error>) + 'static)> {
2094            Some(&self.0)
2095        }
2096
2097        #[inline]
2098        fn error(&self, error: Error) {
2099            (self.0)(Err(error));
2100        }
2101    }
2102
2103    let Some(shared) = shared.upgrade() else {
2104        callback(Err(Error::new(ErrorKind::NotConnected(
2105            "WebSocket service is down",
2106        ))));
2107        return Request::new();
2108    };
2109
2110    if shared.state.get() != State::Open {
2111        callback(Err(Error::new(ErrorKind::NotConnected(
2112            "WebSocket is not connected",
2113        ))));
2114        return Request::new();
2115    }
2116
2117    let serial = shared.serial.get();
2118    shared.serial.set(serial.wrapping_add(1));
2119
2120    let pending = Pending {
2121        id: MessageId::CONNECT,
2122        serial,
2123        callback: RequestCallbackImpl(callback),
2124    };
2125
2126    let existing = shared
2127        .g
2128        .requests
2129        .borrow_mut()
2130        .insert(serial, Box::new(pending));
2131
2132    if let Some(p) = existing {
2133        p.callback.error(Error::new(ErrorKind::Cancelled));
2134    }
2135
2136    if let Err(error) = shared.send_connect(serial) {
2137        // NB: The request is registered before it is sent, since sending
2138        // can observe synchronously that the peer has gone away and fail
2139        // every pending request before it returns. If that did not already
2140        // fail this request, it is failed here.
2141        shared.fail_request(serial, error);
2142        return Request::new();
2143    }
2144
2145    Request {
2146        serial,
2147        g: Rc::downgrade(&shared.g),
2148    }
2149}
2150
2151/// A request builder .
2152///
2153/// Associate the callback to be used by using either
2154/// [`RequestBuilder::on_packet`] or [`RequestBuilder::on_raw_packet`] depending
2155/// on your needs.
2156///
2157/// Send the request with [`RequestBuilder::send`].
2158pub struct RequestBuilder<'a, H, B, C>
2159where
2160    H: WebImpl,
2161{
2162    shared: &'a Weak<Shared<H>>,
2163    channel: Option<ChannelId>,
2164    body: B,
2165    callback: C,
2166}
2167
2168impl<'a, H, B, C> RequestBuilder<'a, H, B, C>
2169where
2170    H: WebImpl,
2171{
2172    /// Set the body of the request.
2173    #[inline]
2174    pub fn body<U>(self, body: U) -> RequestBuilder<'a, H, U, C>
2175    where
2176        U: api::Request,
2177    {
2178        RequestBuilder {
2179            shared: self.shared,
2180            channel: self.channel,
2181            body,
2182            callback: self.callback,
2183        }
2184    }
2185
2186    /// Handle the response using the specified callback.
2187    ///
2188    /// # Examples
2189    ///
2190    /// ```
2191    /// # extern crate yew023 as yew;
2192    /// use yew::prelude::*;
2193    /// use musli_web::web03::prelude::*;
2194    ///
2195    /// mod api {
2196    ///     use musli::{Decode, Encode};
2197    ///     use musli_web::api;
2198    ///
2199    ///     #[derive(Encode, Decode)]
2200    ///     pub struct HelloRequest<'de> {
2201    ///         pub message: &'de str,
2202    ///     }
2203    ///
2204    ///     #[derive(Encode, Decode)]
2205    ///     pub struct HelloResponse<'de> {
2206    ///         pub message: &'de str,
2207    ///     }
2208    ///
2209    ///     api::define! {
2210    ///         pub type Hello;
2211    ///
2212    ///         impl Endpoint for Hello {
2213    ///             impl<'de> Request for HelloRequest<'de>;
2214    ///             type Response<'de> = HelloResponse<'de>;
2215    ///         }
2216    ///     }
2217    /// }
2218    ///
2219    /// enum Msg {
2220    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
2221    /// }
2222    ///
2223    /// #[derive(Properties, PartialEq)]
2224    /// struct Props {
2225    ///     ws: ws::Handle,
2226    /// }
2227    ///
2228    /// struct App {
2229    ///     message: String,
2230    ///     _hello: ws::Request,
2231    /// }
2232    ///
2233    /// impl Component for App {
2234    ///     type Message = Msg;
2235    ///     type Properties = Props;
2236    ///
2237    ///     fn create(ctx: &Context<Self>) -> Self {
2238    ///         let hello = ctx.props().ws
2239    ///             .request()
2240    ///             .body(api::HelloRequest { message: "Hello!"})
2241    ///             .on_packet(ctx.link().callback(Msg::OnHello))
2242    ///             .send();
2243    ///
2244    ///         Self {
2245    ///             message: String::from("No Message :("),
2246    ///             _hello: hello,
2247    ///         }
2248    ///     }
2249    ///
2250    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2251    ///         match msg {
2252    ///             Msg::OnHello(Err(error)) => {
2253    ///                 tracing::error!("Request error: {:?}", error);
2254    ///                 false
2255    ///             }
2256    ///             Msg::OnHello(Ok(packet)) => {
2257    ///                 if let Ok(response) = packet.decode() {
2258    ///                     self.message = response.message.to_owned();
2259    ///                 }
2260    ///
2261    ///                 true
2262    ///             }
2263    ///         }
2264    ///     }
2265    ///
2266    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2267    ///         html! {
2268    ///             <div>
2269    ///                 <h1>{"WebSocket Example"}</h1>
2270    ///                 <p>{format!("Message: {}", self.message)}</p>
2271    ///             </div>
2272    ///         }
2273    ///     }
2274    /// }
2275    /// ```
2276    pub fn on_packet<E>(
2277        self,
2278        callback: impl Callback<Result<Packet<E>>>,
2279    ) -> RequestBuilder<'a, H, B, impl Callback<Result<RawPacket>>>
2280    where
2281        E: api::Endpoint,
2282    {
2283        self.on_raw_packet(move |result: Result<RawPacket>| match result {
2284            Ok(ok) => callback.call(Ok(Packet::new(ok))),
2285            Err(err) => callback.call(Err(err)),
2286        })
2287    }
2288
2289    /// Handle the response using the specified callback.
2290    ///
2291    /// # Examples
2292    ///
2293    /// ```
2294    /// # extern crate yew023 as yew;
2295    /// use yew::prelude::*;
2296    /// use musli_web::web03::prelude::*;
2297    ///
2298    /// mod api {
2299    ///     use musli::{Decode, Encode};
2300    ///     use musli_web::api;
2301    ///
2302    ///     #[derive(Encode, Decode)]
2303    ///     pub struct HelloRequest<'de> {
2304    ///         pub message: &'de str,
2305    ///     }
2306    ///
2307    ///     #[derive(Encode, Decode)]
2308    ///     pub struct HelloResponse<'de> {
2309    ///         pub message: &'de str,
2310    ///     }
2311    ///
2312    ///     api::define! {
2313    ///         pub type Hello;
2314    ///
2315    ///         impl Endpoint for Hello {
2316    ///             impl<'de> Request for HelloRequest<'de>;
2317    ///             type Response<'de> = HelloResponse<'de>;
2318    ///         }
2319    ///     }
2320    /// }
2321    ///
2322    /// enum Msg {
2323    ///     OnHello(Result<ws::RawPacket, ws::Error>),
2324    /// }
2325    ///
2326    /// #[derive(Properties, PartialEq)]
2327    /// struct Props {
2328    ///     ws: ws::Handle,
2329    /// }
2330    ///
2331    /// struct App {
2332    ///     message: String,
2333    ///     _hello: ws::Request,
2334    /// }
2335    ///
2336    /// impl Component for App {
2337    ///     type Message = Msg;
2338    ///     type Properties = Props;
2339    ///
2340    ///     fn create(ctx: &Context<Self>) -> Self {
2341    ///         let link = ctx.link().clone();
2342    ///
2343    ///         let hello = ctx.props().ws
2344    ///             .request()
2345    ///             .body(api::HelloRequest { message: "Hello!"})
2346    ///             .on_raw_packet(move |packet| link.send_message(Msg::OnHello(packet)))
2347    ///             .send();
2348    ///
2349    ///         Self {
2350    ///             message: String::from("No Message :("),
2351    ///             _hello: hello,
2352    ///         }
2353    ///     }
2354    ///
2355    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2356    ///         match msg {
2357    ///             Msg::OnHello(Err(error)) => {
2358    ///                 tracing::error!("Request error: {:?}", error);
2359    ///                 false
2360    ///             }
2361    ///             Msg::OnHello(Ok(packet)) => {
2362    ///                 if let Ok(response) = packet.decode::<api::HelloResponse>() {
2363    ///                     self.message = response.message.to_owned();
2364    ///                 }
2365    ///
2366    ///                 true
2367    ///             }
2368    ///         }
2369    ///     }
2370    ///
2371    ///     fn view(&self, ctx: &Context<Self>) -> Html {
2372    ///         html! {
2373    ///             <div>
2374    ///                 <h1>{"WebSocket Example"}</h1>
2375    ///                 <p>{format!("Message: {}", self.message)}</p>
2376    ///             </div>
2377    ///         }
2378    ///     }
2379    /// }
2380    /// ```
2381    pub fn on_raw_packet<U>(self, callback: U) -> RequestBuilder<'a, H, B, U>
2382    where
2383        U: Callback<Result<RawPacket, Error>>,
2384    {
2385        RequestBuilder {
2386            shared: self.shared,
2387            channel: self.channel,
2388            body: self.body,
2389            callback,
2390        }
2391    }
2392}
2393
2394impl<'a, H, B, C> RequestBuilder<'a, H, B, C>
2395where
2396    B: api::Request,
2397    C: Callback<Result<RawPacket>>,
2398    H: WebImpl,
2399{
2400    /// Send the request.
2401    ///
2402    /// This requires that a body has been set using [`RequestBuilder::body`].
2403    pub fn send(self) -> Request {
2404        struct RequestCallbackImpl<C>(C);
2405
2406        impl<C> RequestCallback for RequestCallbackImpl<C>
2407        where
2408            C: Callback<Result<RawPacket>>,
2409        {
2410            #[inline]
2411            fn as_request(&self) -> Option<&(dyn Callback<Result<RawPacket>> + 'static)> {
2412                Some(&self.0)
2413            }
2414
2415            #[inline]
2416            fn error(&self, error: Error) {
2417                self.0.call(Err(error));
2418            }
2419        }
2420
2421        let Some(shared) = self.shared.upgrade() else {
2422            self.callback.call(Err(Error::new(ErrorKind::NotConnected(
2423                "WebSocket service is down",
2424            ))));
2425            return Request::new();
2426        };
2427
2428        if shared.state.get() != State::Open {
2429            self.callback.call(Err(Error::new(ErrorKind::NotConnected(
2430                "WebSocket is not connected",
2431            ))));
2432            return Request::new();
2433        }
2434
2435        let Some(channel) = self.channel else {
2436            self.callback.call(Err(Error::new(ErrorKind::NotConnected(
2437                "WebSocket request over closed channel",
2438            ))));
2439            return Request::new();
2440        };
2441
2442        let serial = shared.serial.get();
2443        shared.serial.set(serial.wrapping_add(1));
2444
2445        let pending = Pending {
2446            id: <B::Endpoint as api::Endpoint>::ID,
2447            serial,
2448            callback: RequestCallbackImpl(self.callback),
2449        };
2450
2451        let existing = shared
2452            .g
2453            .requests
2454            .borrow_mut()
2455            .insert(serial, Box::new(pending));
2456
2457        if let Some(p) = existing {
2458            p.callback.error(Error::new(ErrorKind::Cancelled));
2459        }
2460
2461        if let Err(error) = shared.send_client_request(serial, channel, &self.body) {
2462            // NB: The request is registered before it is sent, since sending
2463            // can observe synchronously that the peer has gone away and fail
2464            // every pending request before it returns. If that did not already
2465            // fail this request, it is failed here.
2466            shared.fail_request(serial, error);
2467            return Request::new();
2468        }
2469
2470        Request {
2471            serial,
2472            g: Rc::downgrade(&shared.g),
2473        }
2474    }
2475}
2476
2477/// The handle for a pending request.
2478///
2479/// Dropping or [`clear()`] this handle will cancel the request.
2480///
2481/// [`clear()`]: Self::clear
2482pub struct Request {
2483    serial: u32,
2484    g: Weak<Generic>,
2485}
2486
2487impl Request {
2488    /// An empty request handler.
2489    ///
2490    /// # Examples
2491    ///
2492    /// ```
2493    /// use musli_web::web03::prelude::*;
2494    ///
2495    /// let mut request = ws::Request::new();
2496    /// assert_eq!(request.is_pending(), false);
2497    /// ```
2498    #[inline]
2499    pub const fn new() -> Self {
2500        Self {
2501            serial: 0,
2502            g: Weak::new(),
2503        }
2504    }
2505
2506    /// Clear the request handle without dropping it, cancelling any pending
2507    /// requests.
2508    pub fn clear(&mut self) {
2509        let removed = {
2510            let serial = mem::take(&mut self.serial);
2511
2512            let Some(g) = self.g.upgrade() else {
2513                return;
2514            };
2515
2516            self.g = Weak::new();
2517
2518            let Some(p) = g.requests.borrow_mut().remove(&serial) else {
2519                return;
2520            };
2521
2522            p
2523        };
2524
2525        drop(removed);
2526    }
2527
2528    /// Indicates if a request is pending.
2529    ///
2530    /// # Examples
2531    ///
2532    /// ```
2533    /// use musli_web::web03::prelude::*;
2534    ///
2535    /// let mut request = ws::Request::new();
2536    /// assert_eq!(request.is_pending(), false);
2537    /// ```
2538    #[inline]
2539    pub fn is_pending(&self) -> bool {
2540        let Some(g) = self.g.upgrade() else {
2541            return false;
2542        };
2543
2544        g.requests.borrow().contains_key(&self.serial)
2545    }
2546}
2547
2548impl Default for Request {
2549    #[inline]
2550    fn default() -> Self {
2551        Self::new()
2552    }
2553}
2554
2555impl Drop for Request {
2556    #[inline]
2557    fn drop(&mut self) {
2558        self.clear();
2559    }
2560}
2561
2562/// A request in flight which resolves to its decoded response, see
2563/// [`Handle::call`].
2564///
2565/// Dropping it cancels the request, the same way as dropping a [`Request`]
2566/// does.
2567#[must_use = "Futures do nothing unless polled, and dropping this cancels the request"]
2568pub struct Call<T> {
2569    slot: Rc<CallSlot>,
2570    request: Request,
2571    _marker: PhantomData<fn() -> T>,
2572}
2573
2574/// Where the callback of a [`Call`] leaves the outcome of the request.
2575#[derive(Default)]
2576struct CallSlot {
2577    result: Cell<Option<Result<RawPacket>>>,
2578    waker: Cell<Option<Waker>>,
2579}
2580
2581impl<T> Call<T> {
2582    /// Send a request through `builder`, keeping the outcome for the
2583    /// returned future.
2584    fn send<H, B>(builder: RequestBuilder<'_, H, B, EmptyCallback>) -> Self
2585    where
2586        H: WebImpl,
2587        B: api::Request,
2588    {
2589        let slot = Rc::new(CallSlot::default());
2590
2591        // NB: The callback can be called before `send` returns, such as when
2592        // the request is not connected. The slot then already has the outcome
2593        // when the future is first polled.
2594        let request = builder
2595            .on_raw_packet({
2596                let slot = slot.clone();
2597
2598                move |result: Result<RawPacket>| {
2599                    slot.result.set(Some(result));
2600
2601                    if let Some(waker) = slot.waker.take() {
2602                        waker.wake();
2603                    }
2604                }
2605            })
2606            .send();
2607
2608        Self {
2609            slot,
2610            request,
2611            _marker: PhantomData,
2612        }
2613    }
2614
2615    /// Indicates if the request is still waiting for its response.
2616    ///
2617    /// Once this is `false`, polling the future no longer has to wait.
2618    #[inline]
2619    pub fn is_pending(&self) -> bool {
2620        self.request.is_pending()
2621    }
2622}
2623
2624impl<T> Future for Call<T>
2625where
2626    for<'de> T: DecodeBody<'de>,
2627{
2628    type Output = Result<T>;
2629
2630    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2631        let this = self.get_mut();
2632
2633        let Some(result) = this.slot.result.take() else {
2634            this.slot.waker.set(Some(cx.waker().clone()));
2635            return Poll::Pending;
2636        };
2637
2638        Poll::Ready(result.and_then(|packet| packet.decode()))
2639    }
2640}
2641
2642impl<T> fmt::Debug for Call<T> {
2643    #[inline]
2644    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2645        f.debug_struct("Call")
2646            .field("type", &any::type_name::<T>())
2647            .field("is_pending", &self.is_pending())
2648            .finish()
2649    }
2650}
2651
2652/// A set of pending requests, kept alive until each completes.
2653///
2654/// Dropping a [`Request`] cancels it, so a component with several requests
2655/// in flight at once has to keep every one of them somewhere. Push each one
2656/// sent into a `Requests` with [`Requests::push`]. A request stays pending
2657/// until it completes in any way, by its response, an error, or the
2658/// connection being lost, and the set forgets it once it has.
2659///
2660/// Every request still pending is cancelled when the set is dropped or
2661/// [`cleared`], so a component which keeps a set cancels what it sent once
2662/// it goes away.
2663///
2664/// To keep at most one request for each of a number of things, such as one
2665/// fetch per row, use [`KeyedRequests`] instead.
2666///
2667/// [`cleared`]: Requests::clear
2668///
2669/// # Examples
2670///
2671/// ```
2672/// # extern crate yew023 as yew;
2673/// use yew::prelude::*;
2674/// use musli_web::web03::prelude::*;
2675///
2676/// mod api {
2677///     use musli::{Decode, Encode};
2678///     use musli_web::api;
2679///
2680///     #[derive(Encode, Decode)]
2681///     pub struct SaveRequest<'de> {
2682///         pub text: &'de str,
2683///     }
2684///
2685///     api::define! {
2686///         pub type Save;
2687///
2688///         impl Endpoint for Save {
2689///             impl<'de> Request for SaveRequest<'de>;
2690///             type Response<'de> = ();
2691///         }
2692///     }
2693/// }
2694///
2695/// enum Msg {
2696///     Save(String),
2697///     Saved(Result<ws::Packet<api::Save>, ws::Error>),
2698/// }
2699///
2700/// #[derive(Properties, PartialEq)]
2701/// struct Props {
2702///     ws: ws::Handle,
2703/// }
2704///
2705/// struct Notes {
2706///     // Every save sent which has not completed yet.
2707///     saves: ws::Requests,
2708/// }
2709///
2710/// impl Component for Notes {
2711///     type Message = Msg;
2712///     type Properties = Props;
2713///
2714///     fn create(_: &Context<Self>) -> Self {
2715///         Self {
2716///             saves: ws::Requests::new(),
2717///         }
2718///     }
2719///
2720///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2721///         match msg {
2722///             Msg::Save(text) => {
2723///                 // Saving again does not cancel an earlier save.
2724///                 self.saves.push(
2725///                     ctx.props()
2726///                         .ws
2727///                         .request()
2728///                         .body(api::SaveRequest { text: &text })
2729///                         .on_packet(ctx.link().callback(Msg::Saved))
2730///                         .send(),
2731///                 );
2732///
2733///                 true
2734///             }
2735///             Msg::Saved(result) => {
2736///                 if let Err(error) = result {
2737///                     tracing::error!("Save failed: {error}");
2738///                 }
2739///
2740///                 true
2741///             }
2742///         }
2743///     }
2744///
2745///     fn view(&self, ctx: &Context<Self>) -> Html {
2746///         let onclick = ctx.link().callback(|_: MouseEvent| Msg::Save(String::from("Hello")));
2747///
2748///         html! {
2749///             <>
2750///                 <button {onclick}>{"Save"}</button>
2751///                 if !self.saves.is_empty() {
2752///                     <p>{format!("Saving {}...", self.saves.len())}</p>
2753///                 }
2754///             </>
2755///         }
2756///     }
2757/// }
2758/// ```
2759#[derive(Default)]
2760pub struct Requests {
2761    requests: Vec<Request>,
2762}
2763
2764impl Requests {
2765    /// Construct an empty set of requests.
2766    ///
2767    /// # Examples
2768    ///
2769    /// ```
2770    /// use musli_web::web03::prelude::*;
2771    ///
2772    /// let requests = ws::Requests::new();
2773    /// assert!(requests.is_empty());
2774    /// ```
2775    #[inline]
2776    pub const fn new() -> Self {
2777        Self {
2778            requests: Vec::new(),
2779        }
2780    }
2781
2782    /// Keep `request` until it completes.
2783    ///
2784    /// A request which is not pending, such as one which could not be sent,
2785    /// is dropped straight away.
2786    pub fn push(&mut self, request: Request) {
2787        if !request.is_pending() {
2788            return;
2789        }
2790
2791        // NB: Completed requests are only forgotten when the set would
2792        // otherwise have to grow, which keeps pushing amortized constant time
2793        // while holding at most twice as many requests as were ever pending
2794        // at once.
2795        if self.requests.len() == self.requests.capacity() {
2796            self.requests.retain(Request::is_pending);
2797        }
2798
2799        self.requests.push(request);
2800    }
2801
2802    /// The number of requests which are still pending.
2803    pub fn len(&self) -> usize {
2804        self.requests.iter().filter(|r| r.is_pending()).count()
2805    }
2806
2807    /// Whether no request is pending.
2808    pub fn is_empty(&self) -> bool {
2809        !self.requests.iter().any(Request::is_pending)
2810    }
2811
2812    /// Cancel every pending request.
2813    pub fn clear(&mut self) {
2814        let requests = mem::take(&mut self.requests);
2815        // NB: Dropped once the set is empty, since cancelling a request drops
2816        // its callback.
2817        drop(requests);
2818    }
2819}
2820
2821impl fmt::Debug for Requests {
2822    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2823        f.debug_struct("Requests")
2824            .field("len", &self.len())
2825            .finish()
2826    }
2827}
2828
2829impl Extend<Request> for Requests {
2830    fn extend<I>(&mut self, iter: I)
2831    where
2832        I: IntoIterator<Item = Request>,
2833    {
2834        for request in iter {
2835            self.push(request);
2836        }
2837    }
2838}
2839
2840/// A set of pending requests with at most one for each key, kept alive until
2841/// each completes.
2842///
2843/// This is like [`Requests`], except that each request is stored under a key
2844/// with [`KeyedRequests::insert`]. Storing a request under a key which already
2845/// has one cancels the request stored before it, so that what is fetched for
2846/// a key is always the latest. Any number of keys can have a request in
2847/// flight at once, and a key is forgotten once its request completes.
2848///
2849/// Every request still pending is cancelled when the set is dropped or
2850/// [`cleared`].
2851///
2852/// [`cleared`]: KeyedRequests::clear
2853///
2854/// # Examples
2855///
2856/// ```
2857/// # extern crate yew023 as yew;
2858/// use yew::prelude::*;
2859/// use musli_web::web03::prelude::*;
2860///
2861/// mod api {
2862///     use musli::{Decode, Encode};
2863///     use musli_web::api;
2864///
2865///     #[derive(Encode, Decode)]
2866///     pub struct RenameRequest<'de> {
2867///         pub id: u32,
2868///         pub name: &'de str,
2869///     }
2870///
2871///     api::define! {
2872///         pub type Rename;
2873///
2874///         impl Endpoint for Rename {
2875///             impl<'de> Request for RenameRequest<'de>;
2876///             type Response<'de> = ();
2877///         }
2878///     }
2879/// }
2880///
2881/// enum Msg {
2882///     Rename(u32, String),
2883///     Renamed(Result<ws::Packet<api::Rename>, ws::Error>),
2884/// }
2885///
2886/// #[derive(Properties, PartialEq)]
2887/// struct Props {
2888///     ws: ws::Handle,
2889///     rows: Vec<u32>,
2890/// }
2891///
2892/// struct Rows {
2893///     // At most one rename in flight for each row.
2894///     renames: ws::KeyedRequests<u32>,
2895/// }
2896///
2897/// impl Component for Rows {
2898///     type Message = Msg;
2899///     type Properties = Props;
2900///
2901///     fn create(_: &Context<Self>) -> Self {
2902///         Self {
2903///             renames: ws::KeyedRequests::new(),
2904///         }
2905///     }
2906///
2907///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
2908///         match msg {
2909///             Msg::Rename(id, name) => {
2910///                 // Renaming a row again cancels its earlier rename, but
2911///                 // leaves the renames of other rows alone.
2912///                 self.renames.insert(
2913///                     id,
2914///                     ctx.props()
2915///                         .ws
2916///                         .request()
2917///                         .body(api::RenameRequest { id, name: &name })
2918///                         .on_packet(ctx.link().callback(Msg::Renamed))
2919///                         .send(),
2920///                 );
2921///
2922///                 true
2923///             }
2924///             Msg::Renamed(_) => true,
2925///         }
2926///     }
2927///
2928///     fn view(&self, ctx: &Context<Self>) -> Html {
2929///         html! {
2930///             {for ctx.props().rows.iter().copied().map(|id| {
2931///                 let onclick = ctx.link().callback(move |_: MouseEvent| {
2932///                     Msg::Rename(id, format!("Row {id}"))
2933///                 });
2934///
2935///                 let label = if self.renames.is_pending(&id) {
2936///                     String::from("Renaming...")
2937///                 } else {
2938///                     format!("Rename #{id}")
2939///                 };
2940///
2941///                 html!(<button {onclick}>{label}</button>)
2942///             })}
2943///         }
2944///     }
2945/// }
2946/// ```
2947pub struct KeyedRequests<K> {
2948    requests: HashMap<K, Request>,
2949}
2950
2951impl<K> KeyedRequests<K> {
2952    /// Construct an empty set of requests.
2953    ///
2954    /// # Examples
2955    ///
2956    /// ```
2957    /// use musli_web::web03::prelude::*;
2958    ///
2959    /// let requests = ws::KeyedRequests::<u32>::new();
2960    /// assert!(requests.is_empty());
2961    /// ```
2962    #[inline]
2963    pub fn new() -> Self {
2964        Self {
2965            requests: HashMap::new(),
2966        }
2967    }
2968
2969    /// The number of keys whose request is still pending.
2970    pub fn len(&self) -> usize {
2971        self.requests.values().filter(|r| r.is_pending()).count()
2972    }
2973
2974    /// Whether no request is pending.
2975    pub fn is_empty(&self) -> bool {
2976        !self.requests.values().any(Request::is_pending)
2977    }
2978
2979    /// Iterate over the keys whose request is still pending, in no
2980    /// particular order.
2981    pub fn keys(&self) -> impl Iterator<Item = &K> {
2982        self.requests
2983            .iter()
2984            .filter(|(_, r)| r.is_pending())
2985            .map(|(k, _)| k)
2986    }
2987
2988    /// Cancel every pending request.
2989    pub fn clear(&mut self) {
2990        let requests = mem::take(&mut self.requests);
2991        // NB: Dropped once the set is empty, since cancelling a request drops
2992        // its callback.
2993        drop(requests);
2994    }
2995}
2996
2997impl<K> KeyedRequests<K>
2998where
2999    K: Eq + Hash,
3000{
3001    /// Keep `request` under `key` until it completes, cancelling the request
3002    /// stored under `key` before it.
3003    ///
3004    /// A request which is not pending, such as one which could not be sent,
3005    /// is dropped straight away, but still cancels the one before it.
3006    pub fn insert(&mut self, key: K, request: Request) {
3007        if !request.is_pending() {
3008            let old = self.requests.remove(&key);
3009            drop(old);
3010            return;
3011        }
3012
3013        // NB: Completed requests are only forgotten when the set would
3014        // otherwise have to grow, see `Requests::push`.
3015        if self.requests.len() == self.requests.capacity() {
3016            self.requests.retain(|_, r| r.is_pending());
3017        }
3018
3019        let old = self.requests.insert(key, request);
3020        drop(old);
3021    }
3022
3023    /// Cancel the request stored under `key`, returning whether it was still
3024    /// pending.
3025    pub fn remove<Q>(&mut self, key: &Q) -> bool
3026    where
3027        K: core::borrow::Borrow<Q>,
3028        Q: ?Sized + Eq + Hash,
3029    {
3030        let Some(request) = self.requests.remove(key) else {
3031            return false;
3032        };
3033
3034        let pending = request.is_pending();
3035        drop(request);
3036        pending
3037    }
3038
3039    /// Whether the request stored under `key` is still pending.
3040    pub fn is_pending<Q>(&self, key: &Q) -> bool
3041    where
3042        K: core::borrow::Borrow<Q>,
3043        Q: ?Sized + Eq + Hash,
3044    {
3045        self.requests.get(key).is_some_and(Request::is_pending)
3046    }
3047}
3048
3049impl<K> Default for KeyedRequests<K> {
3050    #[inline]
3051    fn default() -> Self {
3052        Self::new()
3053    }
3054}
3055
3056impl<K> fmt::Debug for KeyedRequests<K>
3057where
3058    K: fmt::Debug,
3059{
3060    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3061        f.debug_set().entries(self.keys()).finish()
3062    }
3063}
3064
3065/// The handle for a pending request.
3066///
3067/// Dropping or calling [`clear()`] on this handle remove the listener.
3068///
3069/// [`clear()`]: Self::clear
3070pub struct Listener {
3071    kind: Option<MessageId>,
3072    index: usize,
3073    g: Weak<Generic>,
3074}
3075
3076impl Listener {
3077    /// Construct an empty listener.
3078    #[inline]
3079    pub const fn new() -> Self {
3080        Self {
3081            kind: None,
3082            index: 0,
3083            g: Weak::new(),
3084        }
3085    }
3086
3087    /// Build up an empty listener with the specified kind.
3088    #[inline]
3089    pub(crate) const fn empty_with_kind(kind: MessageId) -> Self {
3090        Self {
3091            kind: Some(kind),
3092            index: 0,
3093            g: Weak::new(),
3094        }
3095    }
3096
3097    /// Clear the listener without dropping it.
3098    ///
3099    /// This will remove the associated broadcast listener from being notified.
3100    pub fn clear(&mut self) {
3101        // Gather values here to drop them outside of the upgrade block.
3102        let removed;
3103        let removed_value;
3104
3105        {
3106            let Some(g) = self.g.upgrade() else {
3107                return;
3108            };
3109
3110            self.g = Weak::new();
3111            let index = mem::take(&mut self.index);
3112
3113            let Some(kind) = self.kind.take() else {
3114                return;
3115            };
3116
3117            let mut broadcasts = g.broadcasts.borrow_mut();
3118
3119            let Entry::Occupied(mut e) = broadcasts.entry(kind) else {
3120                return;
3121            };
3122
3123            removed = e.get_mut().try_remove(index);
3124
3125            if e.get().is_empty() {
3126                removed_value = Some(e.remove());
3127            } else {
3128                removed_value = None;
3129            }
3130        }
3131
3132        // Drop here, to avoid invoking any destructors which might borrow
3133        // shared mutably earlier.
3134        drop(removed);
3135        drop(removed_value);
3136    }
3137}
3138
3139impl Default for Listener {
3140    #[inline]
3141    fn default() -> Self {
3142        Self::new()
3143    }
3144}
3145
3146impl Drop for Listener {
3147    #[inline]
3148    fn drop(&mut self) {
3149        self.clear();
3150    }
3151}
3152
3153/// The handle for state change listening.
3154///
3155/// Dropping or calling [`clear()`] on this handle will remove the associated
3156/// callback from being notified.
3157///
3158/// [`clear()`]: Self::clear
3159pub struct StateListener {
3160    index: usize,
3161    g: Weak<Generic>,
3162}
3163
3164impl StateListener {
3165    /// Construct an empty state listener.
3166    #[inline]
3167    pub const fn new() -> Self {
3168        Self {
3169            index: 0,
3170            g: Weak::new(),
3171        }
3172    }
3173
3174    /// Clear the state listener without dropping it.
3175    ///
3176    /// This will remove the associated callback from being notified.
3177    pub fn clear(&mut self) {
3178        let removed = {
3179            let Some(g) = self.g.upgrade() else {
3180                return;
3181            };
3182
3183            self.g = Weak::new();
3184
3185            g.state_listeners.borrow_mut().try_remove(self.index)
3186        };
3187
3188        drop(removed);
3189    }
3190}
3191
3192impl Default for StateListener {
3193    #[inline]
3194    fn default() -> Self {
3195        Self::new()
3196    }
3197}
3198
3199impl Drop for StateListener {
3200    #[inline]
3201    fn drop(&mut self) {
3202        self.clear();
3203    }
3204}
3205
3206pub(crate) struct BufData {
3207    /// Buffer being used.
3208    pub(crate) data: Vec<u8>,
3209    /// Number of strong references to this buffer.
3210    strong: Cell<usize>,
3211    /// Reference to shared state where the buffer will be recycled to.
3212    g: Weak<Generic>,
3213}
3214
3215impl BufData {
3216    fn with_capacity(g: Weak<Generic>, capacity: usize) -> Self {
3217        Self {
3218            data: Vec::with_capacity(capacity),
3219            strong: Cell::new(0),
3220            g,
3221        }
3222    }
3223
3224    unsafe fn dec(ptr: NonNull<BufData>) {
3225        unsafe {
3226            let count = ptr.as_ref().strong.get().wrapping_sub(1);
3227            ptr.as_ref().strong.set(count);
3228
3229            if count > 0 {
3230                return;
3231            }
3232
3233            let mut buf = Box::from_raw(ptr.as_ptr());
3234
3235            // Try to recycle the buffer if shared is available, else let it be
3236            // dropped and free here.
3237            let Some(g) = buf.as_ref().g.upgrade() else {
3238                return;
3239            };
3240
3241            let mut buffers = g.buffers.borrow_mut();
3242
3243            // NB: The next message is written from the start of the buffer, so
3244            // the contents of this one must not linger.
3245            buf.data.clear();
3246
3247            // We size our buffers to some max capacity to avod overuse in case
3248            // we infrequently need to handle some massive message. If we don't
3249            // shrink the allocation, then memory use can run away over time.
3250            buf.data.shrink_to(MAX_CAPACITY);
3251
3252            buffers.push_back(buf);
3253        }
3254    }
3255
3256    unsafe fn inc(ptr: NonNull<BufData>) {
3257        unsafe {
3258            let count = ptr.as_ref().strong.get().wrapping_add(1);
3259
3260            if count == 0 {
3261                std::process::abort();
3262            }
3263
3264            ptr.as_ref().strong.set(count);
3265        }
3266    }
3267}
3268
3269/// A shared buffer of data that is recycled when dropped.
3270struct BufRc {
3271    data: NonNull<BufData>,
3272}
3273
3274impl BufRc {
3275    fn new(data: Box<BufData>) -> Self {
3276        let data = NonNull::from(Box::leak(data));
3277
3278        unsafe {
3279            BufData::inc(data);
3280        }
3281
3282        Self { data }
3283    }
3284}
3285
3286impl Deref for BufRc {
3287    type Target = [u8];
3288
3289    fn deref(&self) -> &Self::Target {
3290        unsafe { &(*self.data.as_ptr()).data }
3291    }
3292}
3293
3294impl Clone for BufRc {
3295    fn clone(&self) -> Self {
3296        unsafe {
3297            BufData::inc(self.data);
3298        }
3299
3300        Self { data: self.data }
3301    }
3302}
3303
3304impl Drop for BufRc {
3305    fn drop(&mut self) {
3306        unsafe {
3307            BufData::dec(self.data);
3308        }
3309    }
3310}
3311
3312/// A raw packet of data.
3313#[derive(Clone)]
3314pub struct RawPacket {
3315    id: MessageId,
3316    buf: Option<BufRc>,
3317    at: Cell<usize>,
3318    format: Format,
3319    channel: ChannelId,
3320}
3321
3322impl RawPacket {
3323    /// Construct an empty raw packet.
3324    ///
3325    /// # Examples
3326    ///
3327    /// ```
3328    /// use musli_web::api::MessageId;
3329    /// use musli_web::web::RawPacket;
3330    ///
3331    /// let packet = RawPacket::empty();
3332    ///
3333    /// assert!(packet.is_empty());
3334    /// assert_eq!(packet.id(), MessageId::EMPTY);
3335    /// ```
3336    pub const fn empty() -> Self {
3337        Self {
3338            id: MessageId::EMPTY,
3339            buf: None,
3340            at: Cell::new(0),
3341            format: Format::DEFAULT,
3342            channel: ChannelId::NONE,
3343        }
3344    }
3345
3346    /// The [`Format`] the body of this packet is encoded with.
3347    ///
3348    /// # Examples
3349    ///
3350    /// ```
3351    /// use musli_web::api::Format;
3352    /// use musli_web::web::RawPacket;
3353    ///
3354    /// let packet = RawPacket::empty();
3355    /// assert_eq!(packet.format(), Format::DEFAULT);
3356    /// ```
3357    #[inline]
3358    pub fn format(&self) -> Format {
3359        self.format
3360    }
3361
3362    /// Return the channel this packet belongs to.
3363    ///
3364    /// For a response this is the channel the request was sent over, and for
3365    /// a broadcast it is the channel the broadcast originated from, as written
3366    /// by [`ws::Server::broadcast_from`]. A page can compare it to the id of its
3367    /// own channel to recognize the echo of a change it made itself, see
3368    /// [`RawPacket::is_from`].
3369    ///
3370    /// This is [`ChannelId::NONE`] for a request which was not sent over a
3371    /// channel, and for a broadcast which no channel is credited with, such as
3372    /// one written with [`ws::Server::broadcast`].
3373    ///
3374    /// [`ws::Server::broadcast`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast
3375    /// [`ws::Server::broadcast_from`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast_from
3376    #[inline]
3377    pub fn channel(&self) -> ChannelId {
3378        self.channel
3379    }
3380
3381    /// Test if this packet originated from `channel`.
3382    ///
3383    /// This is `true` if the packet is a broadcast which was written with
3384    /// [`ws::Server::broadcast_from`] and `channel` as its origin, or a
3385    /// response to a request sent over `channel`. It is never `true` for
3386    /// [`ChannelId::NONE`], so a broadcast which no channel is credited with
3387    /// is not mistaken for the echo of a page which has not opened a channel
3388    /// yet.
3389    ///
3390    /// Channel ids are unique across every connection to a server by
3391    /// default, so a broadcast caused by another client never matches.
3392    ///
3393    /// [`ws::Server::broadcast_from`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast_from
3394    ///
3395    /// # Examples
3396    ///
3397    /// ```
3398    /// use musli_web::api::ChannelId;
3399    /// use musli_web::web::RawPacket;
3400    ///
3401    /// let packet = RawPacket::empty();
3402    /// assert_eq!(packet.channel(), ChannelId::NONE);
3403    /// assert!(!packet.is_from(ChannelId::NONE));
3404    /// ```
3405    #[inline]
3406    pub fn is_from(&self, channel: ChannelId) -> bool {
3407        channel != ChannelId::NONE && self.channel == channel
3408    }
3409
3410    /// Decode the contents of a raw packet.
3411    ///
3412    /// This can be called multiple times if there are multiple payloads in
3413    /// sequence of the response.
3414    ///
3415    /// You can check if the packet is empty using [`RawPacket::is_empty`].
3416    pub fn decode<'this, T>(&'this self) -> Result<T>
3417    where
3418        T: DecodeBody<'this>,
3419    {
3420        if self.id == MessageId::EMPTY {
3421            return Err(Error::new(ErrorKind::EmptyPacket));
3422        }
3423
3424        let mut at = self.at.get();
3425
3426        match self.format.decode(self.as_slice(), &mut at) {
3427            Ok(value) => {
3428                self.at.set(at);
3429                Ok(value)
3430            }
3431            Err(error) => {
3432                self.at.set(self.len());
3433                Err(Error::decode_packet(error))
3434            }
3435        }
3436    }
3437
3438    /// Get the underlying byte slice of the packet.
3439    ///
3440    /// # Examples
3441    ///
3442    /// ```
3443    /// use musli_web::web::RawPacket;
3444    ///
3445    /// let packet = RawPacket::empty();
3446    /// assert_eq!(packet.as_slice(), &[0u8; 0]);
3447    /// ```
3448    pub fn as_slice(&self) -> &[u8] {
3449        match &self.buf {
3450            Some(buf) => buf.as_ref(),
3451            None => &[],
3452        }
3453    }
3454
3455    /// Get the number of bytes remaining to be decoded in the packet.
3456    ///
3457    /// # Examples
3458    ///
3459    /// ```
3460    /// use musli_web::web::RawPacket;
3461    ///
3462    /// let packet = RawPacket::empty();
3463    /// assert_eq!(packet.remaining(), 0);
3464    /// ```
3465    pub fn remaining(&self) -> usize {
3466        self.as_slice().len().saturating_sub(self.at.get())
3467    }
3468
3469    /// Get the length of the packet.
3470    ///
3471    /// # Examples
3472    ///
3473    /// ```
3474    /// use musli_web::web::RawPacket;
3475    ///
3476    /// let packet = RawPacket::empty();
3477    /// assert_eq!(packet.len(), 0);
3478    /// ```
3479    pub fn len(&self) -> usize {
3480        match &self.buf {
3481            Some(buf) => buf.len(),
3482            None => 0,
3483        }
3484    }
3485
3486    /// Check if the packet is empty.
3487    ///
3488    /// # Examples
3489    ///
3490    /// ```
3491    /// use musli_web::web::RawPacket;
3492    ///
3493    /// let packet = RawPacket::empty();
3494    /// assert!(packet.is_empty());
3495    /// ```
3496    pub fn is_empty(&self) -> bool {
3497        self.at.get() >= self.len()
3498    }
3499
3500    /// The id of the packet this is a response to as specified by
3501    /// [`Endpoint::ID`] or [`Broadcast::ID`].
3502    ///
3503    /// [`Endpoint::ID`]: crate::api::Endpoint::ID
3504    /// [`Broadcast::ID`]: crate::api::Broadcast::ID
3505    pub fn id(&self) -> MessageId {
3506        self.id
3507    }
3508}
3509
3510impl fmt::Debug for RawPacket {
3511    #[inline]
3512    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3513        f.debug_struct("RawPacket")
3514            .field("remaining", &self.remaining())
3515            .finish()
3516    }
3517}
3518
3519/// A typed packet of data.
3520pub struct Packet<T> {
3521    raw: RawPacket,
3522    _marker: PhantomData<T>,
3523}
3524
3525impl<T> Packet<T> {
3526    /// Construct an empty package.
3527    ///
3528    /// # Examples
3529    ///
3530    /// ```
3531    /// use musli_web::api::MessageId;
3532    /// use musli_web::web::Packet;
3533    ///
3534    /// let packet = Packet::<()>::empty();
3535    ///
3536    /// assert!(packet.is_empty());
3537    /// assert_eq!(packet.id(), MessageId::EMPTY);
3538    /// ```
3539    pub const fn empty() -> Self {
3540        Self {
3541            raw: RawPacket::empty(),
3542            _marker: PhantomData,
3543        }
3544    }
3545
3546    /// Return the channel this packet belongs to.
3547    ///
3548    /// For a response this is the channel the request was sent over, and for
3549    /// a broadcast it is the channel the broadcast originated from, as written
3550    /// by [`ws::Server::broadcast_from`]. A page can compare it to the id of its
3551    /// own channel to recognize the echo of a change it made itself, see
3552    /// [`Packet::is_from`].
3553    ///
3554    /// This is [`ChannelId::NONE`] for a request which was not sent over a
3555    /// channel, and for a broadcast which no channel is credited with, such as
3556    /// one written with [`ws::Server::broadcast`].
3557    ///
3558    /// [`ws::Server::broadcast`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast
3559    /// [`ws::Server::broadcast_from`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast_from
3560    #[inline]
3561    pub fn channel(&self) -> ChannelId {
3562        self.raw.channel()
3563    }
3564
3565    /// Test if this packet originated from `channel`.
3566    ///
3567    /// This is `true` if the packet is a broadcast which was written with
3568    /// [`ws::Server::broadcast_from`] and `channel` as its origin, or a
3569    /// response to a request sent over `channel`. It is never `true` for
3570    /// [`ChannelId::NONE`], so a broadcast which no channel is credited with
3571    /// is not mistaken for the echo of a page which has not opened a channel
3572    /// yet.
3573    ///
3574    /// Channel ids are unique across every connection to a server by
3575    /// default, so a broadcast caused by another client never matches.
3576    ///
3577    /// [`ws::Server::broadcast_from`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast_from
3578    ///
3579    /// # Examples
3580    ///
3581    /// ```
3582    /// use musli_web::api::ChannelId;
3583    /// use musli_web::web::Packet;
3584    ///
3585    /// let packet = Packet::<()>::empty();
3586    /// assert_eq!(packet.channel(), ChannelId::NONE);
3587    /// assert!(!packet.is_from(ChannelId::NONE));
3588    /// ```
3589    #[inline]
3590    pub fn is_from(&self, channel: ChannelId) -> bool {
3591        self.raw.is_from(channel)
3592    }
3593
3594    /// The [`Format`] the body of this packet is encoded with.
3595    #[inline]
3596    pub fn format(&self) -> Format {
3597        self.raw.format()
3598    }
3599
3600    /// Construct a new typed package from a raw one.
3601    ///
3602    /// Note that this does not guarantee that the typed package is correct, but
3603    /// the `T` parameter becomes associated with it allowing it to be used
3604    /// automatically with methods such as [`Packet::decode`].
3605    #[inline]
3606    pub fn new(raw: RawPacket) -> Self {
3607        Self {
3608            raw,
3609            _marker: PhantomData,
3610        }
3611    }
3612
3613    /// Convert a packet into a raw packet.
3614    ///
3615    /// To determine which endpoint or broadcast it belongs to the
3616    /// [`RawPacket::id`] method can be used.
3617    pub fn into_raw(self) -> RawPacket {
3618        self.raw
3619    }
3620
3621    /// Get the number of bytes remaining to be decoded in the packet.
3622    ///
3623    /// # Examples
3624    ///
3625    /// ```
3626    /// use musli_web::web::Packet;
3627    ///
3628    /// let packet = Packet::<()>::empty();
3629    /// assert_eq!(packet.remaining(), 0);
3630    /// ```
3631    pub fn remaining(&self) -> usize {
3632        self.raw.remaining()
3633    }
3634
3635    /// Check if the packet is empty.
3636    ///
3637    /// # Examples
3638    ///
3639    /// ```
3640    /// use musli_web::web::Packet;
3641    ///
3642    /// let packet = Packet::<()>::empty();
3643    /// assert!(packet.is_empty());
3644    /// ```
3645    pub fn is_empty(&self) -> bool {
3646        self.raw.is_empty()
3647    }
3648
3649    /// The id of the packet this is a response to as specified by
3650    /// [`Endpoint::ID`] or [`Broadcast::ID`].
3651    ///
3652    /// [`Endpoint::ID`]: crate::api::Endpoint::ID
3653    /// [`Broadcast::ID`]: crate::api::Broadcast::ID
3654    pub fn id(&self) -> MessageId {
3655        self.raw.id()
3656    }
3657}
3658
3659impl<T> Packet<T>
3660where
3661    T: api::Decodable,
3662{
3663    /// Decode the contents of a packet.
3664    ///
3665    /// This can be called multiple times if there are multiple payloads in
3666    /// sequence of the response.
3667    ///
3668    /// You can check if the packet is empty using [`Packet::is_empty`].
3669    pub fn decode(&self) -> Result<T::Type<'_>> {
3670        self.decode_any()
3671    }
3672
3673    /// Decode any contents of a packet.
3674    ///
3675    /// This can be called multiple times if there are multiple payloads in
3676    /// sequence of the response.
3677    ///
3678    /// You can check if the packet is empty using [`Packet::is_empty`].
3679    pub fn decode_any<'de, R>(&'de self) -> Result<R>
3680    where
3681        R: DecodeBody<'de>,
3682    {
3683        self.raw.decode()
3684    }
3685}
3686
3687impl<T> Packet<T>
3688where
3689    T: api::Endpoint,
3690{
3691    /// Decode the contents of a packet.
3692    ///
3693    /// This can be called multiple times if there are multiple payloads in
3694    /// sequence of the response.
3695    ///
3696    /// You can check if the packet is empty using [`Packet::is_empty`].
3697    pub fn decode_response(&self) -> Result<T::Response<'_>> {
3698        self.decode_any_response()
3699    }
3700
3701    /// Decode any contents of a packet.
3702    ///
3703    /// This can be called multiple times if there are multiple payloads in
3704    /// sequence of the response.
3705    ///
3706    /// You can check if the packet is empty using [`Packet::is_empty`].
3707    pub fn decode_any_response<'de, R>(&'de self) -> Result<R>
3708    where
3709        R: DecodeBody<'de>,
3710    {
3711        self.raw.decode()
3712    }
3713}
3714
3715impl<T> Packet<T>
3716where
3717    T: api::Broadcast,
3718{
3719    /// Decode the primary event related to a broadcast.
3720    pub fn decode_event<'de>(&'de self) -> Result<T::Event<'de>>
3721    where
3722        T: api::BroadcastWithEvent,
3723    {
3724        self.decode_event_any()
3725    }
3726
3727    /// Decode any event related to a broadcast.
3728    pub fn decode_event_any<'de, E>(&'de self) -> Result<E>
3729    where
3730        E: Event<Broadcast = T> + DecodeBody<'de>,
3731    {
3732        self.raw.decode()
3733    }
3734}
3735
3736impl<T> Clone for Packet<T> {
3737    #[inline]
3738    fn clone(&self) -> Self {
3739        Self {
3740            raw: self.raw.clone(),
3741            _marker: PhantomData,
3742        }
3743    }
3744}
3745
3746impl<T> fmt::Debug for Packet<T> {
3747    #[inline]
3748    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3749        f.debug_struct("Packet")
3750            .field("type", &any::type_name::<T>())
3751            .field("remaining", &self.remaining())
3752            .finish()
3753    }
3754}
3755
3756/// A handle to the WebSocket service.
3757pub struct Handle<H>
3758where
3759    H: WebImpl,
3760{
3761    shared: Weak<Shared<H>>,
3762}
3763
3764impl<H> Handle<H>
3765where
3766    H: WebImpl,
3767{
3768    /// The [`Format`] currently in effect for message bodies.
3769    ///
3770    /// Before the connection has been opened this is the format which was
3771    /// requested through [`ServiceBuilder::format`]. Once the connection is
3772    /// open it is the format the server actually agreed to, which can differ if
3773    /// the server does not support what was asked for.
3774    pub fn format(&self) -> Format {
3775        let Some(shared) = self.shared.upgrade() else {
3776            return Format::DEFAULT;
3777        };
3778
3779        shared.format.get()
3780    }
3781
3782    /// The [`Mode`] the socket is currently running in.
3783    ///
3784    /// Before the connection has been opened this is the mode which was
3785    /// requested through [`ServiceBuilder::mode`]. Once the connection is open
3786    /// it is the mode which was settled on, which can differ if the server
3787    /// could not carry the negotiated format that way.
3788    pub fn mode(&self) -> Mode {
3789        let Some(shared) = self.shared.upgrade() else {
3790            return Mode::DEFAULT;
3791        };
3792
3793        shared.mode.get()
3794    }
3795
3796    /// The generation of the connection.
3797    ///
3798    /// This counts the number of times the connection has opened, that is
3799    /// reached [`State::Open`]. It is `0` until the connection first opens,
3800    /// and goes up by one every time it opens again after having been closed.
3801    /// A handle which is not connected to a service, such as
3802    /// [`Handle::default`], always reports `0`.
3803    ///
3804    /// The generation is updated before any listener hears of the connection
3805    /// opening, so it can be read from inside [`Handle::on_state_change`] and
3806    /// [`Handle::on_open`] callbacks.
3807    ///
3808    /// Comparing the generation to the one data was last fetched in tells
3809    /// whether it has to be fetched again, see [refetching after a
3810    /// reconnect](crate::web#refetching-after-a-reconnect).
3811    ///
3812    /// # Examples
3813    ///
3814    /// ```
3815    /// use musli_web::web03::prelude::*;
3816    ///
3817    /// let handle = ws::Handle::default();
3818    /// assert_eq!(handle.generation(), 0);
3819    /// ```
3820    pub fn generation(&self) -> u64 {
3821        let Some(shared) = self.shared.upgrade() else {
3822            return 0;
3823        };
3824
3825        shared.g.generation.get()
3826    }
3827
3828    /// Set up a new logical channel to the WebSocket server.
3829    ///
3830    /// A channel can be uniquely identified on the client and server side over
3831    /// a single connection. This means that if you send a request over a
3832    /// channel using [`Channel::request`], the server can access the
3833    /// [`ChannelId`] to determine which channel sent the request and the client
3834    /// has the ability to correlate any responses sent by the server by
3835    /// inspecting [`Packet::channel`] or [`RawPacket::channel`].
3836    ///
3837    /// A broadcast caused by a request over a channel can name that channel as
3838    /// its origin with [`ws::Server::broadcast_from`], which every listener
3839    /// sees as [`Packet::channel`]. This lets a page skip the echo of its own
3840    /// changes with [`Packet::is_from`], without carrying the [`ChannelId`] in
3841    /// the body of the event.
3842    ///
3843    /// The maximum number of channels is implementation defined, but expect it
3844    /// to be relatively low like `65535` (non-zero 16 bits) to reduce payload
3845    /// sizes. Failure to allocate a channel is reported as
3846    /// [`ChannelEvent::Failed`].
3847    ///
3848    /// [`ws::Server::broadcast_from`]: https://docs.rs/musli-web/latest/musli_web/ws/struct.Server.html#method.broadcast_from
3849    ///
3850    /// # Reconnecting
3851    ///
3852    /// The server forgets a channel when the connection it was opened over
3853    /// closes. The [`Channel`] returned by [`ChannelBuilder::open`] takes care
3854    /// of this: it opens itself again every time the connection reopens, so a
3855    /// component holds the same [`Channel`] for its whole life. Every time it
3856    /// opens the callback set with [`ChannelBuilder::on_change`] is told with
3857    /// [`ChannelEvent::Opened`], which is when to send the requests the
3858    /// component needs the channel for. It gets a new id each time, and
3859    /// [`ChannelEvent::Closed`] is reported when it is lost.
3860    ///
3861    /// While the channel is not open [`Channel::is_open`] returns `false`, and
3862    /// requests over it fail with [`Error::is_not_connected`] without being
3863    /// sent, so there is no need to check before sending. A request which
3864    /// should go out as soon as the channel is back can be queued with
3865    /// [`Channel::when_open`].
3866    ///
3867    /// # Examples
3868    ///
3869    /// ```
3870    /// # extern crate yew023 as yew;
3871    /// use yew::prelude::*;
3872    /// use musli_web::web03::prelude::*;
3873    ///
3874    /// enum Msg {
3875    ///     Channel(ws::ChannelEvent),
3876    /// }
3877    ///
3878    /// #[derive(Properties, PartialEq)]
3879    /// struct Props {
3880    ///     ws: ws::Handle,
3881    /// }
3882    ///
3883    /// struct App {
3884    ///     channel: ws::Channel,
3885    /// }
3886    ///
3887    /// impl App {
3888    ///     fn fetch(&mut self, ctx: &Context<Self>) {
3889    ///         // Send the requests this component shows the result of over
3890    ///         // `self.channel`.
3891    ///     }
3892    /// }
3893    ///
3894    /// impl Component for App {
3895    ///     type Message = Msg;
3896    ///     type Properties = Props;
3897    ///
3898    ///     fn create(ctx: &Context<Self>) -> Self {
3899    ///         // The channel is opened once the connection is, and opened
3900    ///         // again every time the connection reopens.
3901    ///         let channel = ctx.props().ws
3902    ///             .channel()
3903    ///             .on_change(ctx.link().callback(Msg::Channel))
3904    ///             .open();
3905    ///
3906    ///         Self { channel }
3907    ///     }
3908    ///
3909    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
3910    ///         match msg {
3911    ///             Msg::Channel(ws::ChannelEvent::Opened(..)) => {
3912    ///                 // Opened for the first time or after a reconnect, so
3913    ///                 // fetch everything again.
3914    ///                 self.fetch(ctx);
3915    ///                 true
3916    ///             }
3917    ///             Msg::Channel(ws::ChannelEvent::Failed(error)) => {
3918    ///                 tracing::error!("Could not open channel: {error}");
3919    ///                 true
3920    ///             }
3921    ///             Msg::Channel(..) => true,
3922    ///         }
3923    ///     }
3924    ///
3925    ///     fn view(&self, ctx: &Context<Self>) -> Html {
3926    ///         html! {
3927    ///             <div>
3928    ///                 <h1>{"WebSocket Example"}</h1>
3929    ///                 <p>{format!("Channel open: {}", self.channel.is_open())}</p>
3930    ///             </div>
3931    ///         }
3932    ///     }
3933    /// }
3934    /// ```
3935    pub fn channel(&self) -> ChannelBuilder<'_, H, EmptyCallback> {
3936        ChannelBuilder {
3937            shared: &self.shared,
3938            callback: EmptyCallback,
3939        }
3940    }
3941
3942    /// Send a request of type `T`.
3943    ///
3944    /// Returns a handle for the request.
3945    ///
3946    /// If the handle is dropped, the request is cancelled.
3947    ///
3948    /// # Examples
3949    ///
3950    /// ```
3951    /// # extern crate yew023 as yew;
3952    /// use yew::prelude::*;
3953    /// use musli_web::web03::prelude::*;
3954    ///
3955    /// mod api {
3956    ///     use musli::{Decode, Encode};
3957    ///     use musli_web::api;
3958    ///
3959    ///     #[derive(Encode, Decode)]
3960    ///     pub struct HelloRequest<'de> {
3961    ///         pub message: &'de str,
3962    ///     }
3963    ///
3964    ///     #[derive(Encode, Decode)]
3965    ///     pub struct HelloResponse<'de> {
3966    ///         pub message: &'de str,
3967    ///     }
3968    ///
3969    ///     api::define! {
3970    ///         pub type Hello;
3971    ///
3972    ///         impl Endpoint for Hello {
3973    ///             impl<'de> Request for HelloRequest<'de>;
3974    ///             type Response<'de> = HelloResponse<'de>;
3975    ///         }
3976    ///     }
3977    /// }
3978    ///
3979    /// enum Msg {
3980    ///     OnHello(Result<ws::Packet<api::Hello>, ws::Error>),
3981    /// }
3982    ///
3983    /// #[derive(Properties, PartialEq)]
3984    /// struct Props {
3985    ///     ws: ws::Handle,
3986    /// }
3987    ///
3988    /// struct App {
3989    ///     message: String,
3990    ///     _hello: ws::Request,
3991    /// }
3992    ///
3993    /// impl Component for App {
3994    ///     type Message = Msg;
3995    ///     type Properties = Props;
3996    ///
3997    ///     fn create(ctx: &Context<Self>) -> Self {
3998    ///         let hello = ctx.props().ws
3999    ///             .request()
4000    ///             .body(api::HelloRequest { message: "Hello!"})
4001    ///             .on_packet(ctx.link().callback(Msg::OnHello))
4002    ///             .send();
4003    ///
4004    ///         Self {
4005    ///             message: String::from("No Message :("),
4006    ///             _hello: hello,
4007    ///         }
4008    ///     }
4009    ///
4010    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
4011    ///         match msg {
4012    ///             Msg::OnHello(Err(error)) => {
4013    ///                 tracing::error!("Request error: {:?}", error);
4014    ///                 false
4015    ///             }
4016    ///             Msg::OnHello(Ok(packet)) => {
4017    ///                 if let Ok(response) = packet.decode() {
4018    ///                     self.message = response.message.to_owned();
4019    ///                 }
4020    ///
4021    ///                 true
4022    ///             }
4023    ///         }
4024    ///     }
4025    ///
4026    ///     fn view(&self, ctx: &Context<Self>) -> Html {
4027    ///         html! {
4028    ///             <div>
4029    ///                 <h1>{"WebSocket Example"}</h1>
4030    ///                 <p>{format!("Message: {}", self.message)}</p>
4031    ///             </div>
4032    ///         }
4033    ///     }
4034    /// }
4035    /// ```
4036    pub fn request(&self) -> RequestBuilder<'_, H, EmptyBody, EmptyCallback> {
4037        RequestBuilder {
4038            shared: &self.shared,
4039            channel: Some(ChannelId::NONE),
4040            body: EmptyBody,
4041            callback: EmptyCallback,
4042        }
4043    }
4044
4045    /// Send a request over the default channel and get a future which
4046    /// resolves to its decoded response.
4047    ///
4048    /// This is an asynchronous alternative to building the request with
4049    /// [`request`] and handling the response with a callback. The returned
4050    /// [`Call`] resolves to the response of the endpoint `body` is a request
4051    /// for, decoded as an owned value. Dropping it before it resolves cancels
4052    /// the request.
4053    ///
4054    /// The request is sent straight away, the future only waits for the
4055    /// response. It has to be driven by something which polls futures, such as
4056    /// [`Scope::send_future`] in yew or `wasm_bindgen_futures::spawn_local`.
4057    /// Note that a future handed to either of them is not dropped when the
4058    /// component goes away, so the request is not cancelled with it.
4059    ///
4060    /// The response type of the endpoint must be owned, which is what the
4061    /// `for<'de> ...: DecodeBody<'de>` bound says: it decodes from any buffer,
4062    /// so it holds on to none of them. A response declared as `type
4063    /// Response<'de> = User;` qualifies, one which borrows such as `type
4064    /// Response<'de> = UserRef<'de>;` does not compile here. For those use
4065    /// [`RequestBuilder::on_packet`] and decode from the [`Packet`] instead.
4066    ///
4067    /// See [`Channel::call`] to call over a channel.
4068    ///
4069    /// [`request`]: Self::request
4070    /// [`Scope::send_future`]: <https://docs.rs/yew/latest/yew/html/struct.Scope.html#method.send_future>
4071    ///
4072    /// # Errors
4073    ///
4074    /// The future resolves to an [`Error`] which tells what went wrong, the
4075    /// same as the one a callback would get:
4076    ///
4077    /// * [`Error::is_not_connected`] if the request was never sent since the
4078    ///   connection is not open.
4079    /// * [`Error::is_connection_lost`] if the connection closed before the
4080    ///   response arrived.
4081    /// * [`Error::is_cancelled`] if another request took its place.
4082    /// * [`Error::as_server_error`] if the handler on the server failed, and
4083    ///   [`Error::server_error`] to decode the typed error it failed with.
4084    /// * [`Error::is_decode`] if the response does not decode as the response
4085    ///   type, for instance since the server is built from another version of
4086    ///   the API.
4087    ///
4088    /// # Examples
4089    ///
4090    /// ```
4091    /// # extern crate yew023 as yew;
4092    /// use yew::prelude::*;
4093    /// use musli_web::web03::prelude::*;
4094    ///
4095    /// mod api {
4096    ///     use musli::{Decode, Encode};
4097    ///     use musli_web::api;
4098    ///
4099    ///     #[derive(Encode, Decode)]
4100    ///     pub struct UserRequest<'de> {
4101    ///         pub name: &'de str,
4102    ///     }
4103    ///
4104    ///     #[derive(Encode, Decode)]
4105    ///     pub struct UserResponse {
4106    ///         pub name: String,
4107    ///         pub age: u32,
4108    ///     }
4109    ///
4110    ///     api::define! {
4111    ///         pub type User;
4112    ///
4113    ///         impl Endpoint for User {
4114    ///             impl<'de> Request for UserRequest<'de>;
4115    ///             type Response<'de> = UserResponse;
4116    ///         }
4117    ///     }
4118    /// }
4119    ///
4120    /// enum Msg {
4121    ///     Age(Result<u32, ws::Error>),
4122    /// }
4123    ///
4124    /// #[derive(Properties, PartialEq)]
4125    /// struct Props {
4126    ///     ws: ws::Handle,
4127    /// }
4128    ///
4129    /// struct Age {
4130    ///     age: Option<u32>,
4131    /// }
4132    ///
4133    /// impl Component for Age {
4134    ///     type Message = Msg;
4135    ///     type Properties = Props;
4136    ///
4137    ///     fn create(ctx: &Context<Self>) -> Self {
4138    ///         let call = ctx.props().ws.call(api::UserRequest { name: "Alice" });
4139    ///
4140    ///         ctx.link().send_future(async move {
4141    ///             Msg::Age(call.await.map(|user| user.age))
4142    ///         });
4143    ///
4144    ///         Self { age: None }
4145    ///     }
4146    ///
4147    ///     fn update(&mut self, _: &Context<Self>, msg: Self::Message) -> bool {
4148    ///         match msg {
4149    ///             Msg::Age(Ok(age)) => {
4150    ///                 self.age = Some(age);
4151    ///                 true
4152    ///             }
4153    ///             Msg::Age(Err(error)) => {
4154    ///                 tracing::error!("Failed to get age: {error}");
4155    ///                 false
4156    ///             }
4157    ///         }
4158    ///     }
4159    ///
4160    ///     fn view(&self, _: &Context<Self>) -> Html {
4161    ///         html! {
4162    ///             if let Some(age) = self.age {
4163    ///                 <p>{format!("Alice is {age}")}</p>
4164    ///             }
4165    ///         }
4166    ///     }
4167    /// }
4168    /// ```
4169    pub fn call<B>(&self, body: B) -> Call<<B::Endpoint as api::Endpoint>::Response<'static>>
4170    where
4171        B: api::Request,
4172        for<'de> <B::Endpoint as api::Endpoint>::Response<'static>: DecodeBody<'de>,
4173    {
4174        Call::send(self.request().body(body))
4175    }
4176
4177    /// Listen for broadcasts of type `T`.
4178    ///
4179    /// Returns a handle for the listener that will cancel the listener if
4180    /// dropped.
4181    ///
4182    /// # Examples
4183    ///
4184    /// ```
4185    /// # extern crate yew023 as yew;
4186    /// use yew::prelude::*;
4187    /// use musli_web::web03::prelude::*;
4188    ///
4189    /// mod api {
4190    ///     use musli::{Decode, Encode};
4191    ///     use musli_web::api;
4192    ///
4193    ///     #[derive(Encode, Decode)]
4194    ///     pub struct TickEvent<'de> {
4195    ///         pub message: &'de str,
4196    ///         pub tick: u32,
4197    ///     }
4198    ///
4199    ///     api::define! {
4200    ///         pub type Tick;
4201    ///
4202    ///         impl Broadcast for Tick {
4203    ///             impl<'de> Event for TickEvent<'de>;
4204    ///         }
4205    ///     }
4206    /// }
4207    ///
4208    /// enum Msg {
4209    ///     Tick(Result<ws::Packet<api::Tick>, ws::Error>),
4210    /// }
4211    ///
4212    /// #[derive(Properties, PartialEq)]
4213    /// struct Props {
4214    ///     ws: ws::Handle,
4215    /// }
4216    ///
4217    /// struct App {
4218    ///     tick: u32,
4219    ///     _listen: ws::Listener,
4220    /// }
4221    ///
4222    /// impl Component for App {
4223    ///     type Message = Msg;
4224    ///     type Properties = Props;
4225    ///
4226    ///     fn create(ctx: &Context<Self>) -> Self {
4227    ///         let listen = ctx.props().ws.on_broadcast(ctx.link().callback(Msg::Tick));
4228    ///
4229    ///         Self {
4230    ///             tick: 0,
4231    ///             _listen: listen,
4232    ///         }
4233    ///     }
4234    ///
4235    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
4236    ///         match msg {
4237    ///             Msg::Tick(Err(error)) => {
4238    ///                 tracing::error!("Tick error: {error}");
4239    ///                 false
4240    ///             }
4241    ///             Msg::Tick(Ok(packet)) => {
4242    ///                 if let Ok(tick) = packet.decode_event() {
4243    ///                     self.tick = tick.tick;
4244    ///                 }
4245    ///
4246    ///                 true
4247    ///             }
4248    ///         }
4249    ///     }
4250    ///
4251    ///     fn view(&self, ctx: &Context<Self>) -> Html {
4252    ///         html! {
4253    ///             <div>
4254    ///                 <h1>{"WebSocket Example"}</h1>
4255    ///                 <p>{format!("Tick: {}", self.tick)}</p>
4256    ///             </div>
4257    ///         }
4258    ///     }
4259    /// }
4260    /// ```
4261    pub fn on_broadcast<T>(&self, callback: impl Callback<Result<Packet<T>>>) -> Listener
4262    where
4263        T: api::Broadcast,
4264    {
4265        self.on_raw_broadcast::<T>(move |result| match result {
4266            Ok(packet) => callback.call(Ok(Packet::new(packet))),
4267            Err(error) => callback.call(Err(error)),
4268        })
4269    }
4270
4271    /// Listen for broadcasts of type `T`.
4272    ///
4273    /// Returns a handle for the listener that will cancel the listener if
4274    /// dropped.
4275    ///
4276    /// # Examples
4277    ///
4278    /// ```
4279    /// # extern crate yew023 as yew;
4280    /// use yew::prelude::*;
4281    /// use musli_web::web03::prelude::*;
4282    ///
4283    /// mod api {
4284    ///     use musli::{Decode, Encode};
4285    ///     use musli_web::api;
4286    ///
4287    ///     #[derive(Encode, Decode)]
4288    ///     pub struct TickEvent<'de> {
4289    ///         pub message: &'de str,
4290    ///         pub tick: u32,
4291    ///     }
4292    ///
4293    ///     api::define! {
4294    ///         pub type Tick;
4295    ///
4296    ///         impl Broadcast for Tick {
4297    ///             impl<'de> Event for TickEvent<'de>;
4298    ///         }
4299    ///     }
4300    /// }
4301    ///
4302    /// enum Msg {
4303    ///     Tick(Result<ws::RawPacket, ws::Error>),
4304    /// }
4305    ///
4306    /// #[derive(Properties, PartialEq)]
4307    /// struct Props {
4308    ///     ws: ws::Handle,
4309    /// }
4310    ///
4311    /// struct App {
4312    ///     tick: u32,
4313    ///     _listen: ws::Listener,
4314    /// }
4315    ///
4316    /// impl Component for App {
4317    ///     type Message = Msg;
4318    ///     type Properties = Props;
4319    ///
4320    ///     fn create(ctx: &Context<Self>) -> Self {
4321    ///         let link = ctx.link().clone();
4322    ///         let listen = ctx.props().ws.on_raw_broadcast::<api::Tick>(ctx.link().callback(Msg::Tick));
4323    ///
4324    ///         Self {
4325    ///             tick: 0,
4326    ///             _listen: listen,
4327    ///         }
4328    ///     }
4329    ///
4330    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
4331    ///         match msg {
4332    ///             Msg::Tick(Err(error)) => {
4333    ///                 tracing::error!("Tick error: {error}");
4334    ///                 false
4335    ///             }
4336    ///             Msg::Tick(Ok(packet)) => {
4337    ///                 if let Ok(tick) = packet.decode::<api::TickEvent>() {
4338    ///                     self.tick = tick.tick;
4339    ///                 }
4340    ///
4341    ///                 true
4342    ///             }
4343    ///         }
4344    ///     }
4345    ///
4346    ///     fn view(&self, ctx: &Context<Self>) -> Html {
4347    ///         html! {
4348    ///             <div>
4349    ///                 <h1>{"WebSocket Example"}</h1>
4350    ///                 <p>{format!("Tick: {}", self.tick)}</p>
4351    ///             </div>
4352    ///         }
4353    ///     }
4354    /// }
4355    /// ```
4356    pub fn on_raw_broadcast<T>(&self, callback: impl Callback<Result<RawPacket>>) -> Listener
4357    where
4358        T: api::Broadcast,
4359    {
4360        let Some(shared) = self.shared.upgrade() else {
4361            return Listener::empty_with_kind(T::ID);
4362        };
4363
4364        let index = {
4365            let mut broadcasts = shared.g.broadcasts.borrow_mut();
4366            let slots = broadcasts.entry(T::ID).or_default();
4367            slots.insert(Rc::new(callback))
4368        };
4369
4370        Listener {
4371            kind: Some(T::ID),
4372            index,
4373            g: Rc::downgrade(&shared.g),
4374        }
4375    }
4376
4377    /// Listen for state changes to the underlying connection.
4378    ///
4379    /// This indicates when the connection is open and ready to receive requests
4380    /// through [`State::Open`], or if it's closed and requests will be queued
4381    /// through [`State::Closed`]. A server which states another application
4382    /// version is reported through [`State::Incompatible`], see
4383    /// [`ServiceBuilder::app_version`].
4384    ///
4385    /// Note that if you are connecting through a proxy the reported updates
4386    /// might be volatile. It is always best to send a message over the
4387    /// connection on the server side that once received allows the client to
4388    /// know that it is connected.
4389    ///
4390    /// Dropping the returned handle will cancel the listener.
4391    ///
4392    /// # Examples
4393    ///
4394    /// ```
4395    /// # extern crate yew023 as yew;
4396    /// use yew::prelude::*;
4397    /// use musli_web::web03::prelude::*;
4398    ///
4399    /// enum Msg {
4400    ///     StateChange(ws::State),
4401    /// }
4402    ///
4403    /// #[derive(Properties, PartialEq)]
4404    /// struct Props {
4405    ///     ws: ws::Handle,
4406    /// }
4407    ///
4408    /// struct App {
4409    ///     state: ws::State,
4410    ///     _listen: ws::StateListener,
4411    /// }
4412    ///
4413    /// impl Component for App {
4414    ///     type Message = Msg;
4415    ///     type Properties = Props;
4416    ///
4417    ///     fn create(ctx: &Context<Self>) -> Self {
4418    ///         let link = ctx.link().clone();
4419    ///
4420    ///         let (state, listen) = ctx.props().ws.on_state_change(move |state| {
4421    ///             link.send_message(Msg::StateChange(state));
4422    ///         });
4423    ///
4424    ///         Self {
4425    ///             state,
4426    ///             _listen: listen,
4427    ///         }
4428    ///     }
4429    ///
4430    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
4431    ///         match msg {
4432    ///             Msg::StateChange(state) => {
4433    ///                 self.state = state;
4434    ///                 true
4435    ///             }
4436    ///         }
4437    ///     }
4438    ///
4439    ///     fn view(&self, ctx: &Context<Self>) -> Html {
4440    ///         html! {
4441    ///             <div>
4442    ///                 <h1>{"WebSocket Example"}</h1>
4443    ///                 <p>{format!("State: {:?}", self.state)}</p>
4444    ///             </div>
4445    ///         }
4446    ///     }
4447    /// }
4448    pub fn on_state_change(&self, callback: impl Callback<State>) -> (State, StateListener) {
4449        let Some(shared) = self.shared.upgrade() else {
4450            return (
4451                State::Closed,
4452                StateListener {
4453                    index: 0,
4454                    g: Weak::new(),
4455                },
4456            );
4457        };
4458
4459        let (state, index) = {
4460            let index = shared
4461                .g
4462                .state_listeners
4463                .borrow_mut()
4464                .insert(Rc::new(callback));
4465            (shared.state.get(), index)
4466        };
4467
4468        let listener = StateListener {
4469            index,
4470            g: Rc::downgrade(&shared.g),
4471        };
4472
4473        (state, listener)
4474    }
4475
4476    /// Listen for the connection opening.
4477    ///
4478    /// The callback is called with the new [generation] every time the
4479    /// connection reaches [`State::Open`], which is the point at which a
4480    /// component should fetch what it shows again. It is not called when the
4481    /// connection closes.
4482    ///
4483    /// The returned generation is `Some` with the current generation if the
4484    /// connection is open already, in which case the callback is not called
4485    /// for it, and `None` if it is not. A component can fetch straight away
4486    /// if it is `Some`, and otherwise wait for the callback.
4487    ///
4488    /// Dropping the returned handle will cancel the listener.
4489    ///
4490    /// [generation]: Self::generation
4491    ///
4492    /// # Examples
4493    ///
4494    /// ```
4495    /// # extern crate yew023 as yew;
4496    /// use yew::prelude::*;
4497    /// use musli_web::web03::prelude::*;
4498    ///
4499    /// enum Msg {
4500    ///     Opened(u64),
4501    /// }
4502    ///
4503    /// #[derive(Properties, PartialEq)]
4504    /// struct Props {
4505    ///     ws: ws::Handle,
4506    /// }
4507    ///
4508    /// struct App {
4509    ///     /// The generation the data was last fetched in.
4510    ///     fetched: Option<u64>,
4511    ///     _open: ws::StateListener,
4512    /// }
4513    ///
4514    /// impl App {
4515    ///     fn fetch(&mut self, ctx: &Context<Self>, generation: u64) {
4516    ///         if self.fetched == Some(generation) {
4517    ///             return;
4518    ///         }
4519    ///
4520    ///         self.fetched = Some(generation);
4521    ///         // Send the requests this component shows the result of.
4522    ///     }
4523    /// }
4524    ///
4525    /// impl Component for App {
4526    ///     type Message = Msg;
4527    ///     type Properties = Props;
4528    ///
4529    ///     fn create(ctx: &Context<Self>) -> Self {
4530    ///         let (generation, open) = ctx.props().ws.on_open(ctx.link().callback(Msg::Opened));
4531    ///
4532    ///         let mut this = Self {
4533    ///             fetched: None,
4534    ///             _open: open,
4535    ///         };
4536    ///
4537    ///         if let Some(generation) = generation {
4538    ///             this.fetch(ctx, generation);
4539    ///         }
4540    ///
4541    ///         this
4542    ///     }
4543    ///
4544    ///     fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
4545    ///         match msg {
4546    ///             Msg::Opened(generation) => {
4547    ///                 self.fetch(ctx, generation);
4548    ///                 true
4549    ///             }
4550    ///         }
4551    ///     }
4552    ///
4553    ///     fn view(&self, _: &Context<Self>) -> Html {
4554    ///         html! {}
4555    ///     }
4556    /// }
4557    /// ```
4558    pub fn on_open(&self, callback: impl Callback<u64>) -> (Option<u64>, StateListener) {
4559        let Some(shared) = self.shared.upgrade() else {
4560            return (None, StateListener::new());
4561        };
4562
4563        let callback = {
4564            // NB: Weak, since the listener is owned by the generic state.
4565            let g = Rc::downgrade(&shared.g);
4566
4567            move |state: State| {
4568                if state != State::Open {
4569                    return;
4570                }
4571
4572                if let Some(g) = g.upgrade() {
4573                    callback.call(g.generation.get());
4574                }
4575            }
4576        };
4577
4578        let index = shared
4579            .g
4580            .state_listeners
4581            .borrow_mut()
4582            .insert(Rc::new(callback));
4583
4584        let generation = shared
4585            .state
4586            .get()
4587            .is_open()
4588            .then(|| shared.g.generation.get());
4589
4590        let listener = StateListener {
4591            index,
4592            g: Rc::downgrade(&shared.g),
4593        };
4594
4595        (generation, listener)
4596    }
4597}
4598
4599impl<H> Clone for Handle<H>
4600where
4601    H: WebImpl,
4602{
4603    #[inline]
4604    fn clone(&self) -> Self {
4605        Self {
4606            shared: self.shared.clone(),
4607        }
4608    }
4609}
4610
4611/// Construct a default handle that is not connected to a backend.
4612///
4613/// # Examples
4614///
4615/// ```
4616/// use musli_web::web03::prelude::*;
4617///
4618/// let handle = ws::Handle::default();
4619/// ```
4620impl<H> Default for Handle<H>
4621where
4622    H: WebImpl,
4623{
4624    #[inline]
4625    fn default() -> Self {
4626        Self {
4627            shared: Weak::new(),
4628        }
4629    }
4630}
4631
4632impl<H> PartialEq for Handle<H>
4633where
4634    H: WebImpl,
4635{
4636    #[inline]
4637    fn eq(&self, other: &Self) -> bool {
4638        Weak::ptr_eq(&self.shared, &other.shared)
4639    }
4640}
4641
4642impl<H> fmt::Debug for Handle<H>
4643where
4644    H: WebImpl,
4645{
4646    #[inline]
4647    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4648        let mut f = f.debug_struct("Handle");
4649
4650        if let Some(shared) = self.shared.upgrade() {
4651            f.field("connect", &shared.connect);
4652            f.field("state", &shared.state.get());
4653        }
4654
4655        f.finish()
4656    }
4657}
4658
4659/// What happened to a [`Channel`], as told to the callback set with
4660/// [`ChannelBuilder::on_change`].
4661#[derive(Debug)]
4662#[non_exhaustive]
4663pub enum ChannelEvent {
4664    /// The channel was opened over the current connection with the given
4665    /// [`ChannelId`], and requests can be sent over it.
4666    ///
4667    /// This is reported every time the channel opens, including after a
4668    /// reconnect, at which point the server has forgotten everything which
4669    /// was sent over the channel before and the id is likely different.
4670    Opened(ChannelId),
4671    /// The channel was lost along with the connection it was opened over.
4672    ///
4673    /// It opens again by itself once the connection is back.
4674    Closed,
4675    /// The server could not open the channel, for example since it has run
4676    /// out of channel ids or its handler refused it.
4677    ///
4678    /// The channel stays closed until the connection reopens, at which point
4679    /// it is tried again.
4680    Failed(Error),
4681}
4682
4683/// A logical channel to a WebSocket server, which opens itself again every
4684/// time the connection does.
4685///
4686/// A channel is set up with [`Handle::channel`], see it for more details.
4687///
4688/// Cloning a channel is cheap and every clone refers to the same channel. The
4689/// channel is closed and stops reopening once the last clone has been dropped.
4690///
4691/// While the channel is not open, such as before the server has answered or
4692/// while the connection is down, [`Channel::is_open`] returns `false`,
4693/// [`Channel::id`] returns [`ChannelId::NONE`], and requests sent over it fail
4694/// with [`Error::is_not_connected`] without being sent.
4695pub struct Channel<H>
4696where
4697    H: WebImpl,
4698{
4699    inner: Rc<ChannelInner<H>>,
4700}
4701
4702/// The state of a channel shared by its clones.
4703struct ChannelInner<H>
4704where
4705    H: WebImpl,
4706{
4707    handle: Handle<H>,
4708    /// The id of the channel while it is open, or [`ChannelId::NONE`].
4709    id: Cell<ChannelId>,
4710    /// The generation of the connection the channel was last opened over.
4711    generation: Cell<u64>,
4712    on_change: Box<dyn Callback<ChannelEvent>>,
4713    /// Waiting to be called once the channel is open, see
4714    /// [`Channel::when_open`].
4715    queue: RefCell<VecDeque<Box<dyn FnOnce(&Channel<H>)>>>,
4716    /// The pending request to open the channel.
4717    connect: RefCell<Request>,
4718    state: RefCell<StateListener>,
4719}
4720
4721impl<H> ChannelInner<H>
4722where
4723    H: WebImpl,
4724{
4725    fn is_open(&self) -> bool {
4726        let id = self.id.get();
4727
4728        if id == ChannelId::NONE {
4729            return false;
4730        }
4731
4732        let Some(shared) = self.handle.shared.upgrade() else {
4733            return false;
4734        };
4735
4736        shared.state.get().is_open() && shared.g.generation.get() == self.generation.get()
4737    }
4738
4739    fn on_state(self: &Rc<Self>, state: State) {
4740        match state {
4741            State::Open => {
4742                self.connect();
4743            }
4744            State::Closed | State::Incompatible { .. } => {
4745                // NB: Dropped outside of the borrow, since dropping a request
4746                // touches the shared request table.
4747                let connect = mem::take(&mut *self.connect.borrow_mut());
4748                drop(connect);
4749
4750                if self.id.replace(ChannelId::NONE) != ChannelId::NONE {
4751                    self.on_change.call(ChannelEvent::Closed);
4752                }
4753            }
4754        }
4755    }
4756
4757    fn connect(self: &Rc<Self>) {
4758        let request = connect_channel(&self.handle.shared, {
4759            let inner = Rc::downgrade(self);
4760
4761            move |result| {
4762                if let Some(inner) = inner.upgrade() {
4763                    inner.connected(result);
4764                }
4765            }
4766        });
4767
4768        let old = mem::replace(&mut *self.connect.borrow_mut(), request);
4769        drop(old);
4770    }
4771
4772    fn connected(self: &Rc<Self>, result: Result<ChannelId>) {
4773        let id = match result {
4774            Ok(id) => id,
4775            Err(error) => {
4776                // NB: These mean that the connection went away, in which case
4777                // the channel is opened again once it is back.
4778                if !(error.is_connection_lost() || error.is_not_connected() || error.is_cancelled())
4779                {
4780                    self.on_change.call(ChannelEvent::Failed(error));
4781                }
4782
4783                return;
4784            }
4785        };
4786
4787        self.id.set(id);
4788        self.generation.set(self.handle.generation());
4789
4790        let channel = Channel {
4791            inner: self.clone(),
4792        };
4793
4794        // NB: Each call can close the channel, in which case what remains in
4795        // the queue waits for it to open again.
4796        while channel.is_open() {
4797            let Some(f) = self.queue.borrow_mut().pop_front() else {
4798                break;
4799            };
4800
4801            f(&channel);
4802        }
4803
4804        if channel.is_open() && self.id.get() == id {
4805            self.on_change.call(ChannelEvent::Opened(id));
4806        }
4807    }
4808}
4809
4810impl<H> Drop for ChannelInner<H>
4811where
4812    H: WebImpl,
4813{
4814    #[inline]
4815    fn drop(&mut self) {
4816        // NB: A channel from an earlier connection was dropped by the server
4817        // along with that connection, and its id may since have been handed
4818        // to another channel over the current one.
4819        if self.is_open() {
4820            if let Some(shared) = self.handle.shared.upgrade() {
4821                shared.remove_channel(self.id.get());
4822            }
4823        }
4824    }
4825}
4826
4827impl<H> Channel<H>
4828where
4829    H: WebImpl,
4830{
4831    /// The id the server gave the channel.
4832    ///
4833    /// This is [`ChannelId::NONE`] while the channel is not [open], and
4834    /// usually changes each time the channel opens again after a reconnect.
4835    ///
4836    /// [open]: Self::is_open
4837    #[inline]
4838    pub fn id(&self) -> ChannelId {
4839        if self.inner.is_open() {
4840            self.inner.id.get()
4841        } else {
4842            ChannelId::NONE
4843        }
4844    }
4845
4846    /// The [generation] of the connection the channel was last opened over.
4847    ///
4848    /// This is `0` until the channel first opens.
4849    ///
4850    /// [generation]: Handle::generation
4851    #[inline]
4852    pub fn generation(&self) -> u64 {
4853        self.inner.generation.get()
4854    }
4855
4856    /// Whether requests can be sent over this channel.
4857    ///
4858    /// This is `true` from when the server has opened the channel until the
4859    /// connection it was opened over closes. It is `false` for a [default]
4860    /// channel, and while the channel is being opened again after a
4861    /// reconnect. A request over a channel which is not open fails with
4862    /// [`Error::is_not_connected`] without being sent.
4863    ///
4864    /// [default]: Channel::default
4865    ///
4866    /// # Examples
4867    ///
4868    /// ```
4869    /// use musli_web::web03::prelude::*;
4870    ///
4871    /// let channel = ws::Channel::default();
4872    /// assert!(!channel.is_open());
4873    /// ```
4874    #[inline]
4875    pub fn is_open(&self) -> bool {
4876        self.inner.is_open()
4877    }
4878
4879    /// Get the handle this channel was opened through.
4880    ///
4881    /// A handle sheds the channel information and allows for setting up things
4882    /// like broadcast listener.
4883    #[inline]
4884    pub fn handle(&self) -> &Handle<H> {
4885        &self.inner.handle
4886    }
4887
4888    /// Send a request of type `T` over the channel.
4889    ///
4890    /// Returns a handle for the request. If the handle is dropped, the request
4891    /// is cancelled.
4892    ///
4893    /// If the channel is not [open], the request fails with
4894    /// [`Error::is_not_connected`] without being sent. Send it once the
4895    /// channel has opened instead, as reported by [`ChannelEvent::Opened`], or
4896    /// use [`Channel::when_open`]. See [`ChannelBuilder::on_change`] for an
4897    /// example.
4898    ///
4899    /// [open]: Self::is_open
4900    pub fn request(&self) -> RequestBuilder<'_, H, EmptyBody, EmptyCallback> {
4901        RequestBuilder {
4902            shared: &self.inner.handle.shared,
4903            channel: self.inner.is_open().then(|| self.inner.id.get()),
4904            body: EmptyBody,
4905            callback: EmptyCallback,
4906        }
4907    }
4908
4909    /// Send a request over the current channel and get a future which
4910    /// resolves to its decoded response.
4911    ///
4912    /// This is the same as [`Handle::call`] except that the request is sent
4913    /// over this channel, see it for how the response is decoded and the
4914    /// errors it resolves to. Like [`request`], it fails with
4915    /// [`Error::is_not_connected`] without being sent if the channel is not
4916    /// open.
4917    ///
4918    /// [`request`]: Self::request
4919    pub fn call<B>(&self, body: B) -> Call<<B::Endpoint as api::Endpoint>::Response<'static>>
4920    where
4921        B: api::Request,
4922        for<'de> <B::Endpoint as api::Endpoint>::Response<'static>: DecodeBody<'de>,
4923    {
4924        Call::send(self.request().body(body))
4925    }
4926
4927    /// Call `f` with the channel once it is open.
4928    ///
4929    /// If the channel is open, `f` is called straight away. Otherwise it is
4930    /// queued and called as soon as the channel opens, before
4931    /// [`ChannelEvent::Opened`] is reported. Queued calls are made in the order
4932    /// they were queued, and are dropped without being called if the channel
4933    /// is dropped first.
4934    ///
4935    /// This suits a request made in response to the user, which should be
4936    /// sent even if the connection happens to be down at the time.
4937    ///
4938    /// # Examples
4939    ///
4940    /// ```
4941    /// use std::cell::Cell;
4942    /// use std::rc::Rc;
4943    ///
4944    /// use musli_web::web03::prelude::*;
4945    ///
4946    /// let channel = ws::Channel::default();
4947    /// let called = Rc::new(Cell::new(false));
4948    ///
4949    /// channel.when_open({
4950    ///     let called = called.clone();
4951    ///     move |_: &ws::Channel| called.set(true)
4952    /// });
4953    ///
4954    /// // A default channel never opens.
4955    /// assert!(!called.get());
4956    /// ```
4957    pub fn when_open(&self, f: impl FnOnce(&Channel<H>) + 'static) {
4958        if self.inner.is_open() {
4959            f(self);
4960            return;
4961        }
4962
4963        self.inner.queue.borrow_mut().push_back(Box::new(f));
4964    }
4965}
4966
4967impl<H> Clone for Channel<H>
4968where
4969    H: WebImpl,
4970{
4971    #[inline]
4972    fn clone(&self) -> Self {
4973        Self {
4974            inner: self.inner.clone(),
4975        }
4976    }
4977}
4978
4979/// Construct a channel which is not connected to a service and never opens.
4980///
4981/// This is a placeholder for a component which does not have a channel yet.
4982///
4983/// # Examples
4984///
4985/// ```
4986/// use musli_web::web03::prelude::*;
4987///
4988/// let channel = ws::Channel::default();
4989/// assert!(!channel.is_open());
4990/// assert_eq!(channel.id(), ws::ChannelId::NONE);
4991/// ```
4992impl<H> Default for Channel<H>
4993where
4994    H: WebImpl,
4995{
4996    #[inline]
4997    fn default() -> Self {
4998        Self {
4999            inner: Rc::new(ChannelInner {
5000                handle: Handle::default(),
5001                id: Cell::new(ChannelId::NONE),
5002                generation: Cell::new(0),
5003                on_change: Box::new(EmptyCallback),
5004                queue: RefCell::new(VecDeque::new()),
5005                connect: RefCell::new(Request::new()),
5006                state: RefCell::new(StateListener::new()),
5007            }),
5008        }
5009    }
5010}
5011
5012/// Channels are equal if they are opened through the same service and are
5013/// currently open with the same id, or are both closed.
5014///
5015/// So a property holding a channel changes when the channel opens, closes or
5016/// opens again with a new id.
5017impl<H> PartialEq for Channel<H>
5018where
5019    H: WebImpl,
5020{
5021    #[inline]
5022    fn eq(&self, other: &Self) -> bool {
5023        Weak::ptr_eq(&self.inner.handle.shared, &other.inner.handle.shared)
5024            && self.id() == other.id()
5025    }
5026}
5027
5028impl<H> fmt::Debug for Channel<H>
5029where
5030    H: WebImpl,
5031{
5032    #[inline]
5033    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5034        let mut f = f.debug_struct("Channel");
5035
5036        if let Some(shared) = self.inner.handle.shared.upgrade() {
5037            f.field("connect", &shared.connect);
5038            f.field("state", &shared.state.get());
5039        }
5040
5041        f.field("id", &self.id());
5042        f.field("generation", &self.generation());
5043        f.finish()
5044    }
5045}
5046
5047struct Pending<C>
5048where
5049    C: ?Sized,
5050{
5051    id: MessageId,
5052    serial: u32,
5053    callback: C,
5054}
5055
5056impl<C> fmt::Debug for Pending<C> {
5057    #[inline]
5058    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5059        f.debug_struct("Pending")
5060            .field("serial", &self.serial)
5061            .field("id", &self.id)
5062            .finish_non_exhaustive()
5063    }
5064}
5065
5066struct ForcePrefix<'a>(&'a str, char);
5067
5068impl fmt::Display for ForcePrefix<'_> {
5069    #[inline]
5070    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5071        let Self(string, prefix) = *self;
5072        prefix.fmt(f)?;
5073        string.trim_start_matches(prefix).fmt(f)?;
5074        Ok(())
5075    }
5076}