alpaca_websocket/
config.rs1#[derive(Debug, Clone)]
5pub struct WebSocketConfig {
6 pub reconnect_enabled: bool,
8 pub reconnect_max_attempts: u32,
10 pub reconnect_base_delay_ms: u64,
12 pub reconnect_max_delay_ms: u64,
14 pub ping_interval_ms: u64,
16 pub message_buffer_size: usize,
18 pub connection_timeout_ms: u64,
20}
21
22impl Default for WebSocketConfig {
23 fn default() -> Self {
24 Self {
25 reconnect_enabled: true,
26 reconnect_max_attempts: 10,
27 reconnect_base_delay_ms: 1000,
28 reconnect_max_delay_ms: 60000,
29 ping_interval_ms: 30000,
30 message_buffer_size: 1000,
31 connection_timeout_ms: 10000,
32 }
33 }
34}
35
36impl WebSocketConfig {
37 #[must_use]
39 pub fn new() -> Self {
40 Self::default()
41 }
42
43 #[must_use]
45 pub fn no_reconnect(mut self) -> Self {
46 self.reconnect_enabled = false;
47 self
48 }
49
50 #[must_use]
52 pub fn max_reconnect_attempts(mut self, attempts: u32) -> Self {
53 self.reconnect_max_attempts = attempts;
54 self
55 }
56
57 #[must_use]
59 pub fn reconnect_base_delay(mut self, delay_ms: u64) -> Self {
60 self.reconnect_base_delay_ms = delay_ms;
61 self
62 }
63
64 #[must_use]
66 pub fn ping_interval(mut self, interval_ms: u64) -> Self {
67 self.ping_interval_ms = interval_ms;
68 self
69 }
70
71 #[must_use]
73 pub fn buffer_size(mut self, size: usize) -> Self {
74 self.message_buffer_size = size;
75 self
76 }
77
78 #[must_use]
80 pub fn connection_timeout(mut self, timeout_ms: u64) -> Self {
81 self.connection_timeout_ms = timeout_ms;
82 self
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
88pub enum StreamType {
89 Stocks,
91 Crypto,
93 Options,
95 News,
97 Trading,
99}
100
101impl StreamType {
102 #[must_use]
104 pub fn url(&self, is_paper: bool) -> &'static str {
105 match self {
106 StreamType::Stocks => {
107 if is_paper {
108 "wss://stream.data.alpaca.markets/v2/iex"
109 } else {
110 "wss://stream.data.alpaca.markets/v2/sip"
111 }
112 }
113 StreamType::Crypto => "wss://stream.data.alpaca.markets/v1beta3/crypto/us",
114 StreamType::Options => "wss://stream.data.alpaca.markets/v1beta1/options",
115 StreamType::News => "wss://stream.data.alpaca.markets/v1beta1/news",
116 StreamType::Trading => {
117 if is_paper {
118 "wss://paper-api.alpaca.markets/stream"
119 } else {
120 "wss://api.alpaca.markets/stream"
121 }
122 }
123 }
124 }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum ConnectionState {
130 Disconnected,
132 Connecting,
134 Connected,
136 Reconnecting,
138 Failed,
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_websocket_config_default() {
148 let config = WebSocketConfig::default();
149 assert!(config.reconnect_enabled);
150 assert_eq!(config.reconnect_max_attempts, 10);
151 assert_eq!(config.reconnect_base_delay_ms, 1000);
152 }
153
154 #[test]
155 fn test_websocket_config_builder() {
156 let config = WebSocketConfig::new()
157 .no_reconnect()
158 .max_reconnect_attempts(5)
159 .ping_interval(15000)
160 .buffer_size(500);
161
162 assert!(!config.reconnect_enabled);
163 assert_eq!(config.reconnect_max_attempts, 5);
164 assert_eq!(config.ping_interval_ms, 15000);
165 assert_eq!(config.message_buffer_size, 500);
166 }
167
168 #[test]
169 fn test_stream_type_urls() {
170 assert_eq!(
171 StreamType::Stocks.url(true),
172 "wss://stream.data.alpaca.markets/v2/iex"
173 );
174 assert_eq!(
175 StreamType::Stocks.url(false),
176 "wss://stream.data.alpaca.markets/v2/sip"
177 );
178 assert_eq!(
179 StreamType::Crypto.url(true),
180 "wss://stream.data.alpaca.markets/v1beta3/crypto/us"
181 );
182 assert_eq!(
183 StreamType::Options.url(true),
184 "wss://stream.data.alpaca.markets/v1beta1/options"
185 );
186 }
187}