1use crate::{DummyEncoder, ReconnectLimit};
2use codee::{CodecError, Encoder, HybridEncoder};
3use default_struct_builder::DefaultBuilder;
4use leptos::prelude::*;
5use std::marker::PhantomData;
6use std::sync::Arc;
7use thiserror::Error;
8use web_sys::{CloseEvent, Event};
9
10type ArcFnBytes = Arc<dyn Fn(&[u8]) + Send + Sync>;
11
12#[derive(DefaultBuilder)]
14pub struct UseWebSocketOptions<Rx, E, D, Hb, HbCodec>
15where
16 Rx: ?Sized,
17 Hb: Default + Send + Sync + 'static,
18 HbCodec: Encoder<Hb>,
19 HbCodec: HybridEncoder<
20 Hb,
21 <HbCodec as Encoder<Hb>>::Encoded,
22 Error = <HbCodec as Encoder<Hb>>::Error,
23 >,
24{
25 #[builder(skip)]
27 pub(crate) heartbeat: Option<HeartbeatOptions<Hb, HbCodec>>,
28 pub(crate) on_open: Arc<dyn Fn(Event) + Send + Sync>,
30 #[builder(skip)]
32 pub(crate) on_message: Arc<dyn Fn(&Rx) + Send + Sync>,
33 pub(crate) on_message_raw: Arc<dyn Fn(&str) + Send + Sync>,
35 pub(crate) on_message_raw_bytes: ArcFnBytes,
37 #[builder(skip)]
39 pub(crate) on_error: Arc<dyn Fn(UseWebSocketError<E, D>) + Send + Sync>,
40 pub(crate) on_close: Arc<dyn Fn(CloseEvent) + Send + Sync>,
42 pub(crate) reconnect_limit: ReconnectLimit,
45 pub(crate) reconnect_interval: u64,
47 pub(crate) immediate: bool,
51 #[builder(into)]
58 pub(crate) protocols: Signal<Option<Vec<String>>>,
59}
60
61impl<Rx: ?Sized, E, D, Hb, HbCodec> UseWebSocketOptions<Rx, E, D, Hb, HbCodec>
62where
63 Hb: Default + Send + Sync + 'static,
64 HbCodec: Encoder<Hb>,
65 HbCodec: HybridEncoder<
66 Hb,
67 <HbCodec as Encoder<Hb>>::Encoded,
68 Error = <HbCodec as Encoder<Hb>>::Error,
69 >,
70{
71 pub fn on_error<F>(self, handler: F) -> Self
73 where
74 F: Fn(UseWebSocketError<E, D>) + Send + Sync + 'static,
75 {
76 Self {
77 on_error: Arc::new(handler),
78 ..self
79 }
80 }
81
82 pub fn on_message<F>(self, handler: F) -> Self
84 where
85 F: Fn(&Rx) + Send + Sync + 'static,
86 {
87 Self {
88 on_message: Arc::new(handler),
89 ..self
90 }
91 }
92
93 pub fn heartbeat<NewHb, NewHbCodec>(
96 self,
97 interval: u64,
98 ) -> UseWebSocketOptions<Rx, E, D, NewHb, NewHbCodec>
99 where
100 NewHb: Default + Send + Sync + 'static,
101 NewHbCodec: Encoder<NewHb>,
102 NewHbCodec: HybridEncoder<
103 NewHb,
104 <NewHbCodec as Encoder<NewHb>>::Encoded,
105 Error = <NewHbCodec as Encoder<NewHb>>::Error,
106 >,
107 {
108 UseWebSocketOptions {
109 heartbeat: Some(HeartbeatOptions {
110 data: PhantomData::<NewHb>,
111 interval,
112 codec: PhantomData::<NewHbCodec>,
113 }),
114 on_open: self.on_open,
115 on_message: self.on_message,
116 on_message_raw: self.on_message_raw,
117 on_message_raw_bytes: self.on_message_raw_bytes,
118 on_close: self.on_close,
119 on_error: self.on_error,
120 reconnect_limit: self.reconnect_limit,
121 reconnect_interval: self.reconnect_interval,
122 immediate: self.immediate,
123 protocols: self.protocols,
124 }
125 }
126}
127
128impl<Rx: ?Sized, E, D> Default for UseWebSocketOptions<Rx, E, D, (), DummyEncoder> {
129 fn default() -> Self {
130 Self {
131 heartbeat: None,
132 on_open: Arc::new(|_| {}),
133 on_message: Arc::new(|_| {}),
134 on_message_raw: Arc::new(|_| {}),
135 on_message_raw_bytes: Arc::new(|_| {}),
136 on_error: Arc::new(|_| {}),
137 on_close: Arc::new(|_| {}),
138 reconnect_limit: ReconnectLimit::default(),
139 reconnect_interval: 3000,
140 immediate: true,
141 protocols: Default::default(),
142 }
143 }
144}
145
146#[cfg_attr(feature = "ssr", allow(dead_code))]
148pub struct HeartbeatOptions<Hb, HbCodec>
149where
150 Hb: Default + Send + Sync + 'static,
151 HbCodec: Encoder<Hb>,
152 HbCodec: HybridEncoder<
153 Hb,
154 <HbCodec as Encoder<Hb>>::Encoded,
155 Error = <HbCodec as Encoder<Hb>>::Error,
156 >,
157{
158 data: PhantomData<Hb>,
160 pub(crate) interval: u64,
162 codec: PhantomData<HbCodec>,
164}
165
166impl<Hb, HbCodec> Clone for HeartbeatOptions<Hb, HbCodec>
167where
168 Hb: Default + Send + Sync + 'static,
169 HbCodec: Encoder<Hb>,
170 HbCodec: HybridEncoder<
171 Hb,
172 <HbCodec as Encoder<Hb>>::Encoded,
173 Error = <HbCodec as Encoder<Hb>>::Error,
174 >,
175{
176 fn clone(&self) -> Self {
177 *self
178 }
179}
180
181impl<Hb, HbCodec> Copy for HeartbeatOptions<Hb, HbCodec>
182where
183 Hb: Default + Send + Sync + 'static,
184 HbCodec: Encoder<Hb>,
185 HbCodec: HybridEncoder<
186 Hb,
187 <HbCodec as Encoder<Hb>>::Encoded,
188 Error = <HbCodec as Encoder<Hb>>::Error,
189 >,
190{
191}
192
193#[derive(Error, Debug)]
194pub enum UseWebSocketError<E, D> {
195 #[error("WebSocket error event")]
196 Event(Event),
197 #[error("WebSocket codec error: {0}")]
198 Codec(#[from] CodecError<E, D>),
199 #[error("WebSocket heartbeat codec error: {0}")]
200 HeartbeatCodec(String),
201}