1use crate::types::Exchange;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
10pub struct WebSocketConfig {
11 pub exchange: Exchange,
13
14 pub url: String,
16
17 pub connect_timeout: Duration,
19
20 pub timeout: Duration,
22
23 pub ping_interval: Duration,
25
26 pub pong_timeout: Duration,
28
29 pub max_frame_size: usize,
31
32 pub max_message_size: usize,
34
35 pub compression: CompressionConfig,
37
38 pub reconnect: ReconnectConfig,
40
41 pub headers: Vec<(String, String)>,
43
44 pub debug: bool,
46
47 pub failover_urls: Vec<String>,
49
50 pub enable_session_failover: bool,
52
53 pub heartbeat_interval_milliseconds: u64,
55
56 pub heartbeat_timeout_milliseconds: u64,
58
59 pub max_missed_heartbeats: u32,
61
62 pub batch_size: usize,
64
65 pub custom_ping_message: Option<String>,
67
68 pub custom_pong_response: Option<String>,
70}
71
72impl WebSocketConfig {
73 #[must_use]
75 pub fn new(exchange: Exchange, url: String) -> Self {
76 Self {
77 exchange,
78 url,
79 connect_timeout: Duration::from_secs(10),
80 timeout: Duration::from_secs(30),
81 ping_interval: Duration::from_secs(30),
82 pong_timeout: Duration::from_secs(10),
83 max_frame_size: 64 * 1024, max_message_size: 10 * 1024 * 1024, compression: CompressionConfig::default(),
86 reconnect: ReconnectConfig::default(),
87 headers: Vec::new(),
88 debug: false,
89 failover_urls: Vec::new(),
90 enable_session_failover: false,
91 heartbeat_interval_milliseconds: 30000, heartbeat_timeout_milliseconds: 60000, max_missed_heartbeats: 3,
94 batch_size: 32,
95 custom_ping_message: None,
96 custom_pong_response: None,
97 }
98 }
99
100 #[must_use]
102 pub fn builder(exchange: Exchange, url: String) -> WebSocketConfigBuilder {
103 WebSocketConfigBuilder {
104 config: Self::new(exchange, url),
105 }
106 }
107}
108
109pub struct WebSocketConfigBuilder {
111 config: WebSocketConfig,
112}
113
114impl WebSocketConfigBuilder {
115 #[must_use]
117 pub const fn connect_timeout(mut self, timeout: Duration) -> Self {
118 self.config.connect_timeout = timeout;
119 self
120 }
121
122 #[must_use]
124 pub const fn timeout(mut self, timeout: Duration) -> Self {
125 self.config.timeout = timeout;
126 self
127 }
128
129 #[must_use]
131 pub const fn ping_interval(mut self, interval: Duration) -> Self {
132 self.config.ping_interval = interval;
133 self
134 }
135
136 #[must_use]
138 pub const fn pong_timeout(mut self, timeout: Duration) -> Self {
139 self.config.pong_timeout = timeout;
140 self
141 }
142
143 #[must_use]
145 pub const fn max_frame_size(mut self, size: usize) -> Self {
146 self.config.max_frame_size = size;
147 self
148 }
149
150 #[must_use]
152 pub const fn max_message_size(mut self, size: usize) -> Self {
153 self.config.max_message_size = size;
154 self
155 }
156
157 #[must_use]
159 pub const fn compression(mut self, compression: CompressionConfig) -> Self {
160 self.config.compression = compression;
161 self
162 }
163
164 #[must_use]
166 pub const fn reconnect(mut self, reconnect: ReconnectConfig) -> Self {
167 self.config.reconnect = reconnect;
168 self
169 }
170
171 #[must_use]
173 pub fn header(mut self, key: String, value: String) -> Self {
174 self.config.headers.push((key, value));
175 self
176 }
177
178 #[must_use]
180 pub const fn debug(mut self, debug: bool) -> Self {
181 self.config.debug = debug;
182 self
183 }
184
185 #[must_use]
187 pub fn failover_urls(mut self, urls: Vec<String>) -> Self {
188 self.config.enable_session_failover = !urls.is_empty();
189 self.config.failover_urls = urls;
190 self
191 }
192
193 #[must_use]
195 pub const fn heartbeat(mut self, interval_ms: u64, timeout_ms: u64, max_missed: u32) -> Self {
196 self.config.heartbeat_interval_milliseconds = interval_ms;
197 self.config.heartbeat_timeout_milliseconds = timeout_ms;
198 self.config.max_missed_heartbeats = max_missed;
199 self
200 }
201
202 #[must_use]
204 pub const fn batch_size(mut self, size: usize) -> Self {
205 self.config.batch_size = size;
206 self
207 }
208
209 #[must_use]
211 pub fn custom_ping_pong(mut self, ping: Option<String>, pong: Option<String>) -> Self {
212 self.config.custom_ping_message = ping;
213 self.config.custom_pong_response = pong;
214 self
215 }
216
217 #[must_use]
219 pub fn build(self) -> WebSocketConfig {
220 self.config
221 }
222}
223
224#[derive(Debug, Clone)]
226pub struct CompressionConfig {
227 pub enabled: bool,
229
230 pub client_max_window_bits: u8,
232
233 pub server_max_window_bits: u8,
235
236 pub client_no_context_takeover: bool,
238
239 pub server_no_context_takeover: bool,
241}
242
243impl Default for CompressionConfig {
244 fn default() -> Self {
245 Self {
246 enabled: true,
247 client_max_window_bits: 15,
248 server_max_window_bits: 15,
249 client_no_context_takeover: false,
250 server_no_context_takeover: false,
251 }
252 }
253}
254
255impl CompressionConfig {
256 #[must_use]
258 pub fn disabled() -> Self {
259 Self {
260 enabled: false,
261 ..Default::default()
262 }
263 }
264}
265
266#[derive(Debug, Clone)]
268pub struct ReconnectConfig {
269 pub enabled: bool,
271
272 pub max_attempts: u32,
274
275 pub initial_delay: Duration,
277
278 pub max_delay: Duration,
280
281 pub multiplier: f64,
283
284 pub jitter: bool,
286}
287
288impl Default for ReconnectConfig {
289 fn default() -> Self {
290 Self {
291 enabled: true,
292 max_attempts: 0, initial_delay: Duration::from_millis(100),
294 max_delay: Duration::from_secs(30),
295 multiplier: 2.0,
296 jitter: true,
297 }
298 }
299}
300
301impl ReconnectConfig {
302 #[must_use]
304 pub fn disabled() -> Self {
305 Self {
306 enabled: false,
307 ..Default::default()
308 }
309 }
310}