nautilus_betfair/stream/
config.rs1use crate::common::consts::{
19 BETFAIR_STREAM_HOST, BETFAIR_STREAM_PORT, BETFAIR_STREAM_SERVER_HEARTBEAT_MS,
20};
21
22pub const BETFAIR_STREAM_HEARTBEAT_MIN_MS: u64 = 500;
23pub const BETFAIR_STREAM_HEARTBEAT_MAX_MS: u64 = 5_000;
24const DEAD_PEER_TIMEOUT_MIN_SECS: u64 = BETFAIR_STREAM_SERVER_HEARTBEAT_MS
25 .saturating_mul(2)
26 .div_ceil(1_000);
27
28#[derive(Debug, Clone)]
30pub struct BetfairStreamConfig {
31 pub host: String,
33 pub port: u16,
35 pub heartbeat_secs: Option<u64>,
37 pub heartbeat_timeout_secs: Option<u64>,
41 pub reconnect_delay_initial_ms: u64,
43 pub reconnect_delay_max_ms: u64,
45 #[doc(hidden)]
47 pub use_tls: bool,
48}
49
50impl Default for BetfairStreamConfig {
51 fn default() -> Self {
52 Self {
53 host: BETFAIR_STREAM_HOST.to_string(),
54 port: BETFAIR_STREAM_PORT,
55 heartbeat_secs: None,
56 heartbeat_timeout_secs: None,
57 reconnect_delay_initial_ms: 2_000,
58 reconnect_delay_max_ms: 30_000,
59 use_tls: true,
60 }
61 }
62}
63
64impl BetfairStreamConfig {
65 #[must_use]
66 pub fn dead_peer_timeout_secs(&self) -> u64 {
67 self.heartbeat_timeout_secs
68 .unwrap_or(DEAD_PEER_TIMEOUT_MIN_SECS)
69 }
70
71 pub fn validate(&self) -> anyhow::Result<()> {
78 if self.heartbeat_secs == Some(0) {
79 anyhow::bail!("heartbeat_secs must be positive when set");
80 }
81
82 if let Some(timeout_secs) = self.heartbeat_timeout_secs
83 && timeout_secs < DEAD_PEER_TIMEOUT_MIN_SECS
84 {
85 anyhow::bail!(
86 "heartbeat_timeout_secs must cover at least two server heartbeat intervals \
87 ({DEAD_PEER_TIMEOUT_MIN_SECS}s), was {timeout_secs}s",
88 );
89 }
90
91 Ok(())
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use rstest::rstest;
98
99 use super::*;
100
101 #[rstest]
102 fn test_stream_config_defaults() {
103 let config = BetfairStreamConfig::default();
104 assert_eq!(config.host, BETFAIR_STREAM_HOST);
105 assert_eq!(config.port, BETFAIR_STREAM_PORT);
106 assert_eq!(config.heartbeat_secs, None);
107 assert_eq!(config.heartbeat_timeout_secs, None);
108 assert_eq!(config.dead_peer_timeout_secs(), 10);
109 assert_eq!(config.reconnect_delay_initial_ms, 2_000);
110 assert_eq!(config.reconnect_delay_max_ms, 30_000);
111 assert!(config.use_tls);
112 }
113
114 #[rstest]
115 fn test_stream_config_rejects_short_dead_peer_override() {
116 let config = BetfairStreamConfig {
117 heartbeat_timeout_secs: Some(9),
118 ..Default::default()
119 };
120
121 assert!(config.validate().is_err());
122 }
123}