Skip to content
Clone
b453d5d
112 lines 3.3 KB Rust
use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum RedisMode {
#[default]
Standalone,
Sentinel,
Cluster,
ValkeyStandalone,
}
impl RedisMode {
pub fn parse(value: &str) -> Option<Self> {
if value.eq_ignore_ascii_case("standalone") {
Some(Self::Standalone)
} else if value.eq_ignore_ascii_case("sentinel") {
Some(Self::Sentinel)
} else if value.eq_ignore_ascii_case("cluster") {
Some(Self::Cluster)
} else if value.eq_ignore_ascii_case("valkey_standalone")
|| value.eq_ignore_ascii_case("valkey")
{
Some(Self::ValkeyStandalone)
} else {
None
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct RedisConfig {
pub url: Option<String>,
pub mode: Option<RedisMode>,
pub database: Option<u16>,
pub pool_size: Option<usize>,
pub connection_timeout_secs: Option<u64>,
pub username: Option<String>,
pub password: Option<String>,
}
impl RedisConfig {
pub fn new(url: impl Into<String>) -> Self {
Self {
url: Some(url.into()),
..Self::default()
}
}
pub fn url(&self) -> &str {
self.url.as_deref().unwrap_or("")
}
pub fn mode(&self) -> RedisMode {
self.mode.unwrap_or_default()
}
pub fn pool_size(&self) -> usize {
self.pool_size.unwrap_or(8)
}
pub fn connection_timeout(&self) -> Duration {
Duration::from_secs(self.connection_timeout_secs.unwrap_or(2))
}
pub fn validate(&self) -> Result<&str, String> {
if let Some(size) = self.pool_size {
if size == 0 {
return Err("redis.pool_size must be at least 1".to_string());
}
if size > 128 {
return Err(format!("redis.pool_size must not exceed 128, got {size}"));
}
}
let url = self
.url
.as_deref()
.filter(|s| !s.is_empty())
.ok_or_else(|| "redis.url must be set".to_string())?;
match self.mode() {
RedisMode::Standalone | RedisMode::ValkeyStandalone => {
if !(url.starts_with("redis://") || url.starts_with("rediss://")) {
return Err(format!(
"redis.url must start with redis:// or rediss://, got {url:?}"
));
}
}
RedisMode::Cluster => {
if !(url.starts_with("redis://")
|| url.starts_with("rediss://")
|| url.contains(","))
{
return Err(format!(
"redis cluster url must start with redis:// or rediss://, or list multiple hosts comma-separated, got {url:?}"
));
}
}
RedisMode::Sentinel => {
if !(url.starts_with("redis://") || url.starts_with("rediss://")) {
return Err(format!(
"redis sentinel url must start with redis:// or rediss://, got {url:?}"
));
}
}
}
Ok(url)
}
}