use std::time::Duration;
use redis::{ProtocolVersion, RedisConnectionInfo, TlsMode, sentinel::SentinelNodeConnectionInfo};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ServerRole {
#[default]
Master,
Replica,
}
#[derive(Clone)]
pub struct SentinelPoolConfig {
pub(crate) sentinels: Vec<String>,
pub(crate) service_name: String,
pub(crate) role: ServerRole,
pub(crate) max_size: u32,
pub(crate) min_idle: Option<u32>,
pub(crate) connection_timeout: Duration,
pub(crate) idle_timeout: Option<Duration>,
pub(crate) max_lifetime: Option<Duration>,
pub(crate) verify_role_on_checkout: bool,
pub(crate) max_retries: u32,
pub(crate) retry_backoff: Duration,
pub(crate) enable_watcher: bool,
pub(crate) watcher_reconnect_backoff: Duration,
pub(crate) redis_db: Option<i64>,
pub(crate) redis_username: Option<String>,
pub(crate) redis_password: Option<String>,
pub(crate) redis_protocol: Option<ProtocolVersion>,
pub(crate) redis_tls_mode: Option<TlsMode>,
}
impl SentinelPoolConfig {
pub fn new<I, S>(sentinels: I, service_name: impl Into<String>) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
Self {
sentinels: sentinels.into_iter().map(Into::into).collect(),
service_name: service_name.into(),
role: ServerRole::Master,
max_size: 16,
min_idle: None,
connection_timeout: Duration::from_secs(5),
idle_timeout: Some(Duration::from_secs(600)),
max_lifetime: Some(Duration::from_secs(1800)),
verify_role_on_checkout: true,
max_retries: 3,
retry_backoff: Duration::from_millis(100),
enable_watcher: true,
watcher_reconnect_backoff: Duration::from_secs(2),
redis_db: None,
redis_username: None,
redis_password: None,
redis_protocol: None,
redis_tls_mode: None,
}
}
pub fn role(mut self, role: ServerRole) -> Self {
self.role = role;
self
}
pub fn max_size(mut self, max_size: u32) -> Self {
self.max_size = max_size;
self
}
pub fn min_idle(mut self, min_idle: u32) -> Self {
self.min_idle = Some(min_idle);
self
}
pub fn connection_timeout(mut self, timeout: Duration) -> Self {
self.connection_timeout = timeout;
self
}
pub fn idle_timeout(mut self, timeout: Option<Duration>) -> Self {
self.idle_timeout = timeout;
self
}
pub fn max_lifetime(mut self, lifetime: Option<Duration>) -> Self {
self.max_lifetime = lifetime;
self
}
pub fn verify_role_on_checkout(mut self, verify: bool) -> Self {
self.verify_role_on_checkout = verify;
self
}
pub fn max_retries(mut self, retries: u32) -> Self {
self.max_retries = retries;
self
}
pub fn retry_backoff(mut self, backoff: Duration) -> Self {
self.retry_backoff = backoff;
self
}
pub fn enable_watcher(mut self, enable: bool) -> Self {
self.enable_watcher = enable;
self
}
pub fn watcher_reconnect_backoff(mut self, backoff: Duration) -> Self {
self.watcher_reconnect_backoff = backoff;
self
}
pub fn redis_db(mut self, db: i64) -> Self {
self.redis_db = Some(db);
self
}
pub fn redis_username(mut self, username: impl Into<String>) -> Self {
self.redis_username = Some(username.into());
self
}
pub fn redis_password(mut self, password: impl Into<String>) -> Self {
self.redis_password = Some(password.into());
self
}
pub fn redis_protocol(mut self, protocol: ProtocolVersion) -> Self {
self.redis_protocol = Some(protocol);
self
}
pub fn redis_tls_mode(mut self, tls_mode: TlsMode) -> Self {
self.redis_tls_mode = Some(tls_mode);
self
}
pub(crate) fn build_node_connection_info(&self) -> SentinelNodeConnectionInfo {
let mut info = SentinelNodeConnectionInfo::default();
if let Some(tls) = self.redis_tls_mode {
info = info.set_tls_mode(tls);
}
let mut rci = RedisConnectionInfo::default();
let mut touched = false;
if let Some(db) = self.redis_db {
rci = rci.set_db(db);
touched = true;
}
if let Some(u) = &self.redis_username {
rci = rci.set_username(u);
touched = true;
}
if let Some(p) = &self.redis_password {
rci = rci.set_password(p);
touched = true;
}
if let Some(proto) = self.redis_protocol {
rci = rci.set_protocol(proto);
touched = true;
}
if touched {
info = info.set_redis_connection_info(rci);
}
info
}
}
impl std::fmt::Debug for SentinelPoolConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SentinelPoolConfig")
.field("sentinels", &self.sentinels)
.field("service_name", &self.service_name)
.field("role", &self.role)
.field("max_size", &self.max_size)
.field("min_idle", &self.min_idle)
.field("connection_timeout", &self.connection_timeout)
.field("idle_timeout", &self.idle_timeout)
.field("max_lifetime", &self.max_lifetime)
.field("verify_role_on_checkout", &self.verify_role_on_checkout)
.field("max_retries", &self.max_retries)
.field("retry_backoff", &self.retry_backoff)
.field("enable_watcher", &self.enable_watcher)
.field("watcher_reconnect_backoff", &self.watcher_reconnect_backoff)
.field("redis_db", &self.redis_db)
.field("redis_username", &self.redis_username.as_ref().map(|_| "***"))
.field("redis_password", &self.redis_password.as_ref().map(|_| "***"))
.field("redis_protocol", &self.redis_protocol)
.field(
"redis_tls_mode",
&self.redis_tls_mode.map(|m| match m {
TlsMode::Secure => "Secure",
TlsMode::Insecure => "Insecure",
_ => "Other",
}),
)
.finish()
}
}