1use std::{fmt, path::PathBuf};
2
3use redis::RedisError;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use crate::{CreatePoolError, Pool, PoolBuilder, PoolConfig, RedisResult, Runtime};
8
9#[derive(Clone, Debug)]
37#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
38#[cfg_attr(feature = "serde", serde(crate = "serde"))]
39pub struct Config {
40 pub url: Option<String>,
44
45 pub connection: Option<ConnectionInfo>,
47
48 pub pool: Option<PoolConfig>,
50}
51
52impl Config {
53 pub fn create_pool(&self, runtime: Option<Runtime>) -> Result<Pool, CreatePoolError> {
59 let mut builder = self.builder().map_err(CreatePoolError::Config)?;
60 if let Some(runtime) = runtime {
61 builder = builder.runtime(runtime);
62 }
63 builder.build().map_err(CreatePoolError::Build)
64 }
65
66 pub fn builder(&self) -> Result<PoolBuilder, ConfigError> {
72 let manager = match (&self.url, &self.connection) {
73 (Some(url), None) => crate::Manager::new(url.as_str())?,
74 (None, Some(connection)) => crate::Manager::new(connection.clone())?,
75 (None, None) => crate::Manager::new(ConnectionInfo::default())?,
76 (Some(_), Some(_)) => return Err(ConfigError::UrlAndConnectionSpecified),
77 };
78 let pool_config = self.get_pool_config();
79 Ok(Pool::builder(manager).config(pool_config))
80 }
81
82 #[must_use]
85 pub fn get_pool_config(&self) -> PoolConfig {
86 self.pool.unwrap_or_default()
87 }
88
89 #[must_use]
92 pub fn from_url<T: Into<String>>(url: T) -> Config {
93 Config {
94 url: Some(url.into()),
95 connection: None,
96 pool: None,
97 }
98 }
99
100 #[must_use]
103 pub fn from_connection_info<T: Into<ConnectionInfo>>(connection_info: T) -> Config {
104 Config {
105 url: None,
106 connection: Some(connection_info.into()),
107 pool: None,
108 }
109 }
110}
111
112impl Default for Config {
113 fn default() -> Self {
114 Self {
115 url: None,
116 connection: Some(ConnectionInfo::default()),
117 pool: None,
118 }
119 }
120}
121
122#[derive(Clone, Debug)]
127#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
128#[cfg_attr(feature = "serde", serde(crate = "serde"))]
129pub enum ConnectionAddr {
130 Tcp(String, u16),
132
133 TcpTls {
135 host: String,
137
138 port: u16,
140
141 insecure: bool,
150 },
151
152 Unix(PathBuf),
154}
155
156impl Default for ConnectionAddr {
157 fn default() -> Self {
158 Self::Tcp("127.0.0.1".to_string(), 6379)
159 }
160}
161
162impl From<ConnectionAddr> for redis::ConnectionAddr {
163 fn from(addr: ConnectionAddr) -> Self {
164 match addr {
165 ConnectionAddr::Tcp(host, port) => Self::Tcp(host, port),
166 ConnectionAddr::TcpTls {
167 host,
168 port,
169 insecure,
170 } => Self::TcpTls {
171 host,
172 port,
173 insecure,
174 tls_params: None,
175 },
176 ConnectionAddr::Unix(path) => Self::Unix(path),
177 }
178 }
179}
180
181impl From<redis::ConnectionAddr> for ConnectionAddr {
182 fn from(addr: redis::ConnectionAddr) -> Self {
183 match addr {
184 redis::ConnectionAddr::Tcp(host, port) => Self::Tcp(host, port),
185 redis::ConnectionAddr::TcpTls {
186 host,
187 port,
188 insecure,
189 ..
190 } => ConnectionAddr::TcpTls {
191 host,
192 port,
193 insecure,
194 },
195 redis::ConnectionAddr::Unix(path) => Self::Unix(path),
196 }
197 }
198}
199
200#[derive(Clone, Debug, Default)]
204#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
205#[cfg_attr(feature = "serde", serde(crate = "serde"))]
206pub struct ConnectionInfo {
207 pub addr: ConnectionAddr,
209
210 #[cfg_attr(feature = "serde", serde(flatten))]
212 pub redis: RedisConnectionInfo,
213}
214
215impl From<ConnectionInfo> for redis::ConnectionInfo {
216 fn from(info: ConnectionInfo) -> Self {
217 Self {
218 addr: info.addr.into(),
219 redis: info.redis.into(),
220 }
221 }
222}
223
224impl From<redis::ConnectionInfo> for ConnectionInfo {
225 fn from(info: redis::ConnectionInfo) -> Self {
226 Self {
227 addr: info.addr.into(),
228 redis: info.redis.into(),
229 }
230 }
231}
232
233impl redis::IntoConnectionInfo for ConnectionInfo {
234 fn into_connection_info(self) -> RedisResult<redis::ConnectionInfo> {
235 Ok(self.into())
236 }
237}
238
239#[derive(Clone, Debug, Default)]
243#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
244#[cfg_attr(feature = "serde", serde(crate = "serde"))]
245pub struct RedisConnectionInfo {
246 pub db: i64,
248
249 pub username: Option<String>,
251
252 pub password: Option<String>,
254
255 pub protocol: ProtocolVersion,
257}
258
259#[derive(Clone, Eq, PartialEq, Default, Debug, Copy)]
263#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
264#[cfg_attr(feature = "serde", serde(crate = "serde"))]
265pub enum ProtocolVersion {
266 #[default]
268 RESP2,
269 RESP3,
271}
272
273impl From<RedisConnectionInfo> for redis::RedisConnectionInfo {
274 fn from(info: RedisConnectionInfo) -> Self {
275 let protocol = match info.protocol {
276 ProtocolVersion::RESP2 => redis::ProtocolVersion::RESP2,
277 ProtocolVersion::RESP3 => redis::ProtocolVersion::RESP3,
278 };
279 Self {
280 db: info.db,
281 username: info.username,
282 password: info.password,
283 protocol,
284 }
285 }
286}
287
288impl From<redis::RedisConnectionInfo> for RedisConnectionInfo {
289 fn from(info: redis::RedisConnectionInfo) -> Self {
290 let protocol = match info.protocol {
291 redis::ProtocolVersion::RESP2 => ProtocolVersion::RESP2,
292 redis::ProtocolVersion::RESP3 => ProtocolVersion::RESP3,
293 };
294 Self {
295 db: info.db,
296 username: info.username,
297 password: info.password,
298 protocol,
299 }
300 }
301}
302
303#[derive(Debug)]
305pub enum ConfigError {
306 UrlAndConnectionSpecified,
308 Redis(RedisError),
310}
311
312impl From<RedisError> for ConfigError {
313 fn from(e: RedisError) -> Self {
314 Self::Redis(e)
315 }
316}
317
318impl fmt::Display for ConfigError {
319 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320 match self {
321 Self::UrlAndConnectionSpecified => write!(
322 f,
323 "url and connection must not be specified at the same time."
324 ),
325 Self::Redis(e) => write!(f, "Redis: {}", e),
326 }
327 }
328}
329
330impl std::error::Error for ConfigError {}