nautilus_network/websocket/config.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Configuration for WebSocket client connections.
17//!
18//! # Reconnection Strategy
19//!
20//! The default configuration uses unlimited reconnection attempts (`reconnect_max_attempts: None`).
21//! This is intentional for trading systems because:
22//! - Venues may be down for extended periods but eventually recover.
23//! - Exponential backoff already prevents resource waste.
24//! - Automatic recovery can be useful when manual intervention is not desirable.
25//!
26//! Use `Some(n)` primarily for testing, development, or non-critical connections.
27
28use std::fmt::Debug;
29
30use super::types::{MessageHandler, PingHandler};
31
32/// Configuration for WebSocket client connections.
33///
34/// # Connection Modes
35///
36/// The `message_handler` field determines the connection mode:
37///
38/// ## Handler Mode (`message_handler: Some(...)`)
39///
40/// - Use with [`crate::websocket::WebSocketClient::connect`].
41/// - Client spawns internal task to read messages and call handler.
42/// - Supports automatic reconnection with exponential backoff.
43/// - Reconnection config fields (`reconnect_*`) are active.
44/// - Best for long-lived connections, Python bindings, callback-based APIs.
45///
46/// ## Stream Mode (`message_handler: None`)
47///
48/// - Use with [`crate::websocket::WebSocketClient::connect_stream`].
49/// - Returns a [`MessageReader`](super::types::MessageReader) stream for the caller to read from.
50/// - **Does NOT support automatic reconnection** (reader owned by caller).
51/// - Reconnection config fields are ignored.
52/// - On disconnect, client transitions to CLOSED state and caller must manually reconnect.
53#[cfg_attr(
54 feature = "python",
55 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.network")
56)]
57pub struct WebSocketConfig {
58 /// The URL to connect to.
59 pub url: String,
60 /// The default headers.
61 pub headers: Vec<(String, String)>,
62 /// The function to handle incoming messages.
63 ///
64 /// - `Some(handler)`: Handler mode with automatic reconnection (use with `connect`).
65 /// - `None`: Stream mode without automatic reconnection (use with `connect_stream`).
66 ///
67 /// See [`WebSocketConfig`] docs for detailed explanation of modes.
68 pub message_handler: Option<MessageHandler>,
69 /// The optional heartbeat interval (seconds).
70 pub heartbeat: Option<u64>,
71 /// The optional heartbeat message.
72 pub heartbeat_msg: Option<String>,
73 /// The handler for incoming pings.
74 pub ping_handler: Option<PingHandler>,
75 /// The timeout (milliseconds) for reconnection attempts.
76 /// **Note**: Only applies to handler mode. Ignored in stream mode.
77 pub reconnect_timeout_ms: Option<u64>,
78 /// The initial reconnection delay (milliseconds) for reconnects.
79 /// **Note**: Only applies to handler mode. Ignored in stream mode.
80 pub reconnect_delay_initial_ms: Option<u64>,
81 /// The maximum reconnect delay (milliseconds) for exponential backoff.
82 /// **Note**: Only applies to handler mode. Ignored in stream mode.
83 pub reconnect_delay_max_ms: Option<u64>,
84 /// The exponential backoff factor for reconnection delays.
85 /// **Note**: Only applies to handler mode. Ignored in stream mode.
86 pub reconnect_backoff_factor: Option<f64>,
87 /// The maximum jitter (milliseconds) added to reconnection delays.
88 /// **Note**: Only applies to handler mode. Ignored in stream mode.
89 pub reconnect_jitter_ms: Option<u64>,
90 /// The maximum number of reconnection attempts before giving up.
91 /// **Note**: Only applies to handler mode. Ignored in stream mode.
92 /// - `None`: Unlimited reconnection attempts (default, recommended for production).
93 /// - `Some(n)`: After n failed attempts, transition to CLOSED state.
94 pub reconnect_max_attempts: Option<u32>,
95}
96
97impl Debug for WebSocketConfig {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.debug_struct(stringify!(WebSocketConfig))
100 .field("url", &self.url)
101 .field("headers", &self.headers)
102 .field(
103 "message_handler",
104 &self.message_handler.as_ref().map(|_| "<function>"),
105 )
106 .field("heartbeat", &self.heartbeat)
107 .field("heartbeat_msg", &self.heartbeat_msg)
108 .field(
109 "ping_handler",
110 &self.ping_handler.as_ref().map(|_| "<function>"),
111 )
112 .field("reconnect_timeout_ms", &self.reconnect_timeout_ms)
113 .field(
114 "reconnect_delay_initial_ms",
115 &self.reconnect_delay_initial_ms,
116 )
117 .field("reconnect_delay_max_ms", &self.reconnect_delay_max_ms)
118 .field("reconnect_backoff_factor", &self.reconnect_backoff_factor)
119 .field("reconnect_jitter_ms", &self.reconnect_jitter_ms)
120 .field("reconnect_max_attempts", &self.reconnect_max_attempts)
121 .finish()
122 }
123}
124
125impl Clone for WebSocketConfig {
126 fn clone(&self) -> Self {
127 Self {
128 url: self.url.clone(),
129 headers: self.headers.clone(),
130 message_handler: self.message_handler.clone(),
131 heartbeat: self.heartbeat,
132 heartbeat_msg: self.heartbeat_msg.clone(),
133 ping_handler: self.ping_handler.clone(),
134 reconnect_timeout_ms: self.reconnect_timeout_ms,
135 reconnect_delay_initial_ms: self.reconnect_delay_initial_ms,
136 reconnect_delay_max_ms: self.reconnect_delay_max_ms,
137 reconnect_backoff_factor: self.reconnect_backoff_factor,
138 reconnect_jitter_ms: self.reconnect_jitter_ms,
139 reconnect_max_attempts: self.reconnect_max_attempts,
140 }
141 }
142}