reconnecting_websocket/
builder.rs1use std::{fmt::Debug, marker::PhantomData, time::Duration};
2
3use exponential_backoff::Backoff;
4use gloo::net::websocket::{futures::WebSocket, Message};
5
6use crate::{
7 constants::DEFAULT_STABLE_CONNECTION_TIMEOUT, info, Error, Socket, SocketInput, SocketOutput,
8 DEFAULT_BACKOFF_MAX, DEFAULT_BACKOFF_MIN, DEFAULT_MAX_RETRIES,
9};
10
11#[derive(Debug)]
14pub struct SocketBuilder<I, O> {
15 url: String,
16 backoff_min: Duration,
17 backoff_max: Option<Duration>,
18 max_retries: u32,
19 stable_timeout: Duration,
20 _phantom: PhantomData<(I, O)>,
21}
22
23impl<I, O> SocketBuilder<I, O>
24where
25 I: SocketInput,
26 O: SocketOutput,
27 Message: TryFrom<I>,
28 <Message as TryFrom<I>>::Error: Debug,
29 <O as TryFrom<Message>>::Error: Debug,
30{
31 pub fn new(url: String) -> Self {
33 Self {
34 url,
35 backoff_min: DEFAULT_BACKOFF_MIN,
36 backoff_max: DEFAULT_BACKOFF_MAX,
37 max_retries: DEFAULT_MAX_RETRIES,
38 stable_timeout: DEFAULT_STABLE_CONNECTION_TIMEOUT,
39 _phantom: PhantomData,
40 }
41 }
42
43 pub fn set_url(mut self, url: String) -> Self {
45 self.url = url;
46 self
47 }
48
49 pub fn set_backoff_min(mut self, backoff_min: Duration) -> Self {
51 self.backoff_min = backoff_min;
52 self
53 }
54
55 pub fn set_backoff_max(mut self, backoff_max: Option<Duration>) -> Self {
57 self.backoff_max = backoff_max;
58 self
59 }
60
61 pub fn set_max_retries(mut self, max_retries: u32) -> Self {
63 self.max_retries = max_retries;
64 self
65 }
66
67 pub fn set_stable_timeout(mut self, stable_timeout: Duration) -> Self {
72 self.stable_timeout = stable_timeout;
73 self
74 }
75
76 pub fn open(self) -> Result<Socket<I, O>, Error<I, O>> {
82 let SocketBuilder { url, backoff_min, backoff_max, max_retries, stable_timeout, .. } = self;
83
84 if backoff_min == Duration::ZERO {
85 return Err(Error::InvalidConfig("backoff_min must be > 0".to_string()));
86 }
87
88 if let Some(max) = backoff_max.as_ref() {
89 if max.as_millis() > (u32::MAX as u128) {
90 return Err(Error::InvalidConfig(
91 "backoff_max must be <= u32::MAX millis".to_string(),
92 ));
93 }
94 }
95
96 if max_retries == 0 {
97 return Err(Error::InvalidConfig("backoff_retries must be > 0".to_string()));
98 }
99
100 if stable_timeout.as_millis() > (u32::MAX as u128) {
101 return Err(Error::InvalidConfig(
102 "stable_timeout must be <= u32::MAX millis".to_string(),
103 ));
104 }
105 let stable_timeout_millis = stable_timeout.as_millis() as u32;
106
107 info!("Opening reconnecting websocket to {url}");
108 let socket = WebSocket::open(&url)?;
109
110 let backoff = Backoff::new(max_retries, backoff_min, backoff_max);
111
112 Ok(Socket {
113 url,
114 socket: Some(socket),
115 backoff,
116 max_retries,
117 stable_timeout_millis,
118 ..Default::default()
119 })
120 }
121}