rusty_common/websocket/
config.rs

1//! WebSocket configuration
2//!
3//! Provides configuration structures for WebSocket connections.
4
5use crate::types::Exchange;
6use std::time::Duration;
7
8/// WebSocket configuration
9#[derive(Debug, Clone)]
10pub struct WebSocketConfig {
11    /// Exchange identifier
12    pub exchange: Exchange,
13
14    /// Base WebSocket URL
15    pub url: String,
16
17    /// Connection timeout
18    pub connect_timeout: Duration,
19
20    /// Read/write timeout
21    pub timeout: Duration,
22
23    /// Ping interval
24    pub ping_interval: Duration,
25
26    /// Pong timeout
27    pub pong_timeout: Duration,
28
29    /// Maximum frame size (bytes)
30    pub max_frame_size: usize,
31
32    /// Maximum message size (bytes)
33    pub max_message_size: usize,
34
35    /// Compression configuration
36    pub compression: CompressionConfig,
37
38    /// Reconnection configuration
39    pub reconnect: ReconnectConfig,
40
41    /// Custom headers
42    pub headers: Vec<(String, String)>,
43
44    /// Enable debug logging
45    pub debug: bool,
46
47    /// Failover URLs for session failover
48    pub failover_urls: Vec<String>,
49
50    /// Enable session failover
51    pub enable_session_failover: bool,
52
53    /// Heartbeat interval in milliseconds
54    pub heartbeat_interval_milliseconds: u64,
55
56    /// Heartbeat timeout in milliseconds
57    pub heartbeat_timeout_milliseconds: u64,
58
59    /// Maximum missed heartbeats before considering connection dead
60    pub max_missed_heartbeats: u32,
61
62    /// Message batch size for batch processing
63    pub batch_size: usize,
64
65    /// Custom ping message (if exchange requires specific format)
66    pub custom_ping_message: Option<String>,
67
68    /// Custom pong response (if exchange requires specific format)
69    pub custom_pong_response: Option<String>,
70}
71
72impl WebSocketConfig {
73    /// Create a new configuration with defaults
74    #[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,          // 64KB
84            max_message_size: 10 * 1024 * 1024, // 10MB
85            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, // 30 seconds
92            heartbeat_timeout_milliseconds: 60000,  // 60 seconds
93            max_missed_heartbeats: 3,
94            batch_size: 32,
95            custom_ping_message: None,
96            custom_pong_response: None,
97        }
98    }
99
100    /// Builder pattern for configuration
101    #[must_use]
102    pub fn builder(exchange: Exchange, url: String) -> WebSocketConfigBuilder {
103        WebSocketConfigBuilder {
104            config: Self::new(exchange, url),
105        }
106    }
107}
108
109/// Builder for WebSocket configuration
110pub struct WebSocketConfigBuilder {
111    config: WebSocketConfig,
112}
113
114impl WebSocketConfigBuilder {
115    /// Set connection timeout
116    #[must_use]
117    pub const fn connect_timeout(mut self, timeout: Duration) -> Self {
118        self.config.connect_timeout = timeout;
119        self
120    }
121
122    /// Set read/write timeout
123    #[must_use]
124    pub const fn timeout(mut self, timeout: Duration) -> Self {
125        self.config.timeout = timeout;
126        self
127    }
128
129    /// Set ping interval
130    #[must_use]
131    pub const fn ping_interval(mut self, interval: Duration) -> Self {
132        self.config.ping_interval = interval;
133        self
134    }
135
136    /// Set pong timeout
137    #[must_use]
138    pub const fn pong_timeout(mut self, timeout: Duration) -> Self {
139        self.config.pong_timeout = timeout;
140        self
141    }
142
143    /// Set maximum frame size
144    #[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    /// Set maximum message size
151    #[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    /// Set compression configuration
158    #[must_use]
159    pub const fn compression(mut self, compression: CompressionConfig) -> Self {
160        self.config.compression = compression;
161        self
162    }
163
164    /// Set reconnection configuration
165    #[must_use]
166    pub const fn reconnect(mut self, reconnect: ReconnectConfig) -> Self {
167        self.config.reconnect = reconnect;
168        self
169    }
170
171    /// Add a custom header
172    #[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    /// Enable debug logging
179    #[must_use]
180    pub const fn debug(mut self, debug: bool) -> Self {
181        self.config.debug = debug;
182        self
183    }
184
185    /// Add failover URLs
186    #[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    /// Set heartbeat configuration
194    #[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    /// Set batch size for message processing
203    #[must_use]
204    pub const fn batch_size(mut self, size: usize) -> Self {
205        self.config.batch_size = size;
206        self
207    }
208
209    /// Set custom ping/pong messages
210    #[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    /// Build the configuration
218    #[must_use]
219    pub fn build(self) -> WebSocketConfig {
220        self.config
221    }
222}
223
224/// Compression configuration
225#[derive(Debug, Clone)]
226pub struct CompressionConfig {
227    /// Enable compression
228    pub enabled: bool,
229
230    /// Client max window bits (9-15)
231    pub client_max_window_bits: u8,
232
233    /// Server max window bits (9-15)
234    pub server_max_window_bits: u8,
235
236    /// Client no context takeover
237    pub client_no_context_takeover: bool,
238
239    /// Server no context takeover
240    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    /// Create a disabled compression config
257    #[must_use]
258    pub fn disabled() -> Self {
259        Self {
260            enabled: false,
261            ..Default::default()
262        }
263    }
264}
265
266/// Reconnection configuration
267#[derive(Debug, Clone)]
268pub struct ReconnectConfig {
269    /// Enable automatic reconnection
270    pub enabled: bool,
271
272    /// Maximum number of reconnection attempts (0 = unlimited)
273    pub max_attempts: u32,
274
275    /// Initial backoff delay
276    pub initial_delay: Duration,
277
278    /// Maximum backoff delay
279    pub max_delay: Duration,
280
281    /// Backoff multiplier
282    pub multiplier: f64,
283
284    /// Add jitter to backoff delays
285    pub jitter: bool,
286}
287
288impl Default for ReconnectConfig {
289    fn default() -> Self {
290        Self {
291            enabled: true,
292            max_attempts: 0, // Unlimited
293            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    /// Create a disabled reconnection config
303    #[must_use]
304    pub fn disabled() -> Self {
305        Self {
306            enabled: false,
307            ..Default::default()
308        }
309    }
310}