redis_oxide/core/
config.rs1use std::time::Duration;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum ProtocolVersion {
8    Resp2,
10    Resp3,
12}
13
14impl Default for ProtocolVersion {
15    fn default() -> Self {
16        Self::Resp2
17    }
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum PoolStrategy {
23    Multiplexed,
25    Pool,
27}
28
29#[derive(Debug, Clone)]
31pub struct PoolConfig {
32    pub strategy: PoolStrategy,
34    pub max_size: usize,
36    pub min_idle: usize,
38    pub connection_timeout: Duration,
40}
41
42impl Default for PoolConfig {
43    fn default() -> Self {
44        Self {
45            strategy: PoolStrategy::Multiplexed,
46            max_size: 10,
47            min_idle: 2,
48            connection_timeout: Duration::from_secs(5),
49        }
50    }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum TopologyMode {
56    Auto,
58    Standalone,
60    Cluster,
62}
63
64#[derive(Debug, Clone)]
66pub struct ConnectionConfig {
67    pub connection_string: String,
69
70    pub password: Option<String>,
72
73    pub database: u8,
75
76    pub connect_timeout: Duration,
78
79    pub operation_timeout: Duration,
81
82    pub tcp_keepalive: Option<Duration>,
84
85    pub topology_mode: TopologyMode,
87
88    pub pool: PoolConfig,
90
91    pub max_redirects: usize,
93
94    pub protocol_version: ProtocolVersion,
96
97    pub sentinel: Option<crate::sentinel::SentinelConfig>,
99
100    pub reconnect: ReconnectConfig,
102}
103
104#[derive(Debug, Clone)]
106pub struct ReconnectConfig {
107    pub enabled: bool,
109
110    pub initial_delay: Duration,
112
113    pub max_delay: Duration,
115
116    pub backoff_multiplier: f64,
118
119    pub max_attempts: Option<usize>,
121}
122
123impl Default for ReconnectConfig {
124    fn default() -> Self {
125        Self {
126            enabled: true,
127            initial_delay: Duration::from_millis(100),
128            max_delay: Duration::from_secs(30),
129            backoff_multiplier: 2.0,
130            max_attempts: None,
131        }
132    }
133}
134
135impl Default for ConnectionConfig {
136    fn default() -> Self {
137        Self {
138            connection_string: "redis://localhost:6379".to_string(),
139            password: None,
140            database: 0,
141            connect_timeout: Duration::from_secs(5),
142            operation_timeout: Duration::from_secs(30),
143            tcp_keepalive: Some(Duration::from_secs(60)),
144            topology_mode: TopologyMode::Auto,
145            pool: PoolConfig::default(),
146            max_redirects: 3,
147            protocol_version: ProtocolVersion::default(),
148            sentinel: None,
149            reconnect: ReconnectConfig::default(),
150        }
151    }
152}
153
154impl ConnectionConfig {
155    pub fn new(connection_string: impl Into<String>) -> Self {
157        Self {
158            connection_string: connection_string.into(),
159            ..Default::default()
160        }
161    }
162
163    #[must_use]
165    pub fn with_password(mut self, password: impl Into<String>) -> Self {
166        self.password = Some(password.into());
167        self
168    }
169
170    #[must_use]
172    pub const fn with_database(mut self, database: u8) -> Self {
173        self.database = database;
174        self
175    }
176
177    #[must_use]
179    pub const fn with_connect_timeout(mut self, timeout: Duration) -> Self {
180        self.connect_timeout = timeout;
181        self
182    }
183
184    #[must_use]
186    pub const fn with_operation_timeout(mut self, timeout: Duration) -> Self {
187        self.operation_timeout = timeout;
188        self
189    }
190
191    #[must_use]
193    pub const fn with_topology_mode(mut self, mode: TopologyMode) -> Self {
194        self.topology_mode = mode;
195        self
196    }
197
198    #[must_use]
200    pub const fn with_pool_config(mut self, pool: PoolConfig) -> Self {
201        self.pool = pool;
202        self
203    }
204
205    #[must_use]
207    pub const fn with_max_redirects(mut self, max: usize) -> Self {
208        self.max_redirects = max;
209        self
210    }
211
212    #[must_use]
214    pub const fn with_protocol_version(mut self, version: ProtocolVersion) -> Self {
215        self.protocol_version = version;
216        self
217    }
218
219    #[must_use]
221    pub fn parse_endpoints(&self) -> Vec<(String, u16)> {
222        let conn_str = self.connection_string.trim();
223
224        let addr_part = conn_str
226            .strip_prefix("redis://")
227            .unwrap_or(conn_str)
228            .strip_prefix("rediss://")
229            .unwrap_or_else(|| conn_str.strip_prefix("redis://").unwrap_or(conn_str));
230
231        addr_part
233            .split(',')
234            .filter_map(|endpoint| {
235                let endpoint = endpoint.trim();
236                if endpoint.is_empty() {
237                    return None;
238                }
239
240                if let Some((host, port_str)) = endpoint.rsplit_once(':') {
242                    if let Ok(port) = port_str.parse::<u16>() {
243                        return Some((host.to_string(), port));
244                    }
245                }
246
247                Some((endpoint.to_string(), 6379))
249            })
250            .collect()
251    }
252}