redis_oxide/core/
config.rs1use std::time::Duration;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum PoolStrategy {
8 Multiplexed,
10 Pool,
12}
13
14#[derive(Debug, Clone)]
16pub struct PoolConfig {
17 pub strategy: PoolStrategy,
19 pub max_size: usize,
21 pub min_idle: usize,
23 pub connection_timeout: Duration,
25}
26
27impl Default for PoolConfig {
28 fn default() -> Self {
29 Self {
30 strategy: PoolStrategy::Multiplexed,
31 max_size: 10,
32 min_idle: 2,
33 connection_timeout: Duration::from_secs(5),
34 }
35 }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum TopologyMode {
41 Auto,
43 Standalone,
45 Cluster,
47}
48
49#[derive(Debug, Clone)]
51pub struct ConnectionConfig {
52 pub connection_string: String,
54
55 pub password: Option<String>,
57
58 pub database: u8,
60
61 pub connect_timeout: Duration,
63
64 pub operation_timeout: Duration,
66
67 pub tcp_keepalive: Option<Duration>,
69
70 pub topology_mode: TopologyMode,
72
73 pub pool: PoolConfig,
75
76 pub max_redirects: usize,
78
79 pub reconnect: ReconnectConfig,
81}
82
83#[derive(Debug, Clone)]
85pub struct ReconnectConfig {
86 pub enabled: bool,
88
89 pub initial_delay: Duration,
91
92 pub max_delay: Duration,
94
95 pub backoff_multiplier: f64,
97
98 pub max_attempts: Option<usize>,
100}
101
102impl Default for ReconnectConfig {
103 fn default() -> Self {
104 Self {
105 enabled: true,
106 initial_delay: Duration::from_millis(100),
107 max_delay: Duration::from_secs(30),
108 backoff_multiplier: 2.0,
109 max_attempts: None,
110 }
111 }
112}
113
114impl Default for ConnectionConfig {
115 fn default() -> Self {
116 Self {
117 connection_string: "redis://localhost:6379".to_string(),
118 password: None,
119 database: 0,
120 connect_timeout: Duration::from_secs(5),
121 operation_timeout: Duration::from_secs(30),
122 tcp_keepalive: Some(Duration::from_secs(60)),
123 topology_mode: TopologyMode::Auto,
124 pool: PoolConfig::default(),
125 max_redirects: 3,
126 reconnect: ReconnectConfig::default(),
127 }
128 }
129}
130
131impl ConnectionConfig {
132 pub fn new(connection_string: impl Into<String>) -> Self {
134 Self {
135 connection_string: connection_string.into(),
136 ..Default::default()
137 }
138 }
139
140 #[must_use]
142 pub fn with_password(mut self, password: impl Into<String>) -> Self {
143 self.password = Some(password.into());
144 self
145 }
146
147 #[must_use]
149 pub const fn with_database(mut self, database: u8) -> Self {
150 self.database = database;
151 self
152 }
153
154 #[must_use]
156 pub const fn with_connect_timeout(mut self, timeout: Duration) -> Self {
157 self.connect_timeout = timeout;
158 self
159 }
160
161 #[must_use]
163 pub const fn with_operation_timeout(mut self, timeout: Duration) -> Self {
164 self.operation_timeout = timeout;
165 self
166 }
167
168 #[must_use]
170 pub const fn with_topology_mode(mut self, mode: TopologyMode) -> Self {
171 self.topology_mode = mode;
172 self
173 }
174
175 #[must_use]
177 pub const fn with_pool_config(mut self, pool: PoolConfig) -> Self {
178 self.pool = pool;
179 self
180 }
181
182 #[must_use]
184 pub const fn with_max_redirects(mut self, max: usize) -> Self {
185 self.max_redirects = max;
186 self
187 }
188
189 #[must_use]
191 pub fn parse_endpoints(&self) -> Vec<(String, u16)> {
192 let conn_str = self.connection_string.trim();
193
194 let addr_part = conn_str
196 .strip_prefix("redis://")
197 .unwrap_or(conn_str)
198 .strip_prefix("rediss://")
199 .unwrap_or_else(|| conn_str.strip_prefix("redis://").unwrap_or(conn_str));
200
201 addr_part
203 .split(',')
204 .filter_map(|endpoint| {
205 let endpoint = endpoint.trim();
206 if endpoint.is_empty() {
207 return None;
208 }
209
210 if let Some((host, port_str)) = endpoint.rsplit_once(':') {
212 if let Ok(port) = port_str.parse::<u16>() {
213 return Some((host.to_string(), port));
214 }
215 }
216
217 Some((endpoint.to_string(), 6379))
219 })
220 .collect()
221 }
222}