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}