use crate::error::Result;
use async_trait::async_trait;
use redis::{Cmd, ConnectionInfo, IntoConnectionInfo, Pipeline, RedisFuture, Value};
pub enum RedisConnection {
Single(redis::aio::MultiplexedConnection),
#[cfg(feature = "cluster")]
Cluster(redis::cluster_async::ClusterConnection),
}
#[async_trait]
impl redis::aio::ConnectionLike for RedisConnection {
fn req_packed_command<'a>(&'a mut self, cmd: &'a Cmd) -> RedisFuture<'a, Value> {
match self {
RedisConnection::Single(c) => c.req_packed_command(cmd),
#[cfg(feature = "cluster")]
RedisConnection::Cluster(c) => c.req_packed_command(cmd),
}
}
fn req_packed_commands<'a>(
&'a mut self,
cmd: &'a Pipeline,
offset: usize,
count: usize,
) -> RedisFuture<'a, Vec<Value>> {
match self {
RedisConnection::Single(c) => c.req_packed_commands(cmd, offset, count),
#[cfg(feature = "cluster")]
RedisConnection::Cluster(c) => c.req_packed_commands(cmd, offset, count),
}
}
fn get_db(&self) -> i64 {
0
}
}
#[derive(Clone)]
pub enum RedisConnectionType {
Single {
connection_info: ConnectionInfo,
#[cfg(feature = "tls")]
tls_certs: Option<redis::TlsCertificates>,
},
#[cfg(feature = "cluster")]
Cluster(Vec<ConnectionInfo>),
#[cfg(feature = "sentinel")]
Sentinel {
master_name: String,
sentinels: Vec<ConnectionInfo>,
redis_connection_info: Option<redis::RedisConnectionInfo>,
#[cfg(feature = "tls")]
tls_certs: Option<redis::TlsCertificates>,
},
}
impl RedisConnectionType {
pub fn single<T: IntoConnectionInfo>(connection_info: T) -> Result<Self> {
Ok(Self::Single {
connection_info: connection_info.into_connection_info()?,
#[cfg(feature = "tls")]
tls_certs: None,
})
}
#[cfg(feature = "tls")]
pub fn single_with_tls<T: IntoConnectionInfo>(
connection_info: T,
tls_certs: redis::TlsCertificates,
) -> Result<Self> {
Ok(Self::Single {
connection_info: connection_info.into_connection_info()?,
tls_certs: Some(tls_certs),
})
}
#[cfg(feature = "cluster")]
pub fn cluster<T: IntoConnectionInfo>(nodes: Vec<T>) -> Result<Self> {
let nodes = nodes
.into_iter()
.map(|x| x.into_connection_info())
.filter_map(|x| x.ok())
.collect::<Vec<_>>();
if nodes.is_empty() {
return Err(crate::error::Error::other(
"At least one valid node is required for cluster connection",
));
}
Ok(Self::Cluster(nodes))
}
#[cfg(feature = "sentinel")]
pub fn sentinel<T: IntoConnectionInfo>(
master_name: &str,
sentinels: Vec<T>,
redis_connection_info: Option<redis::RedisConnectionInfo>,
) -> Result<Self> {
let nodes = sentinels
.into_iter()
.map(|x| x.into_connection_info())
.filter_map(|x| x.ok())
.collect::<Vec<_>>();
if nodes.is_empty() {
return Err(crate::error::Error::other(
"At least one valid sentinel node is required for sentinel connection",
));
}
Ok(Self::Sentinel {
master_name: master_name.to_string(),
sentinels: nodes,
redis_connection_info,
#[cfg(feature = "tls")]
tls_certs: None,
})
}
#[cfg(all(feature = "sentinel", feature = "tls"))]
pub fn sentinel_with_tls<T: IntoConnectionInfo>(
master_name: &str,
sentinels: Vec<T>,
redis_connection_info: Option<redis::RedisConnectionInfo>,
tls_certs: redis::TlsCertificates,
) -> Result<Self> {
let nodes = sentinels
.into_iter()
.map(|x| x.into_connection_info())
.filter_map(|x| x.ok())
.collect::<Vec<_>>();
if nodes.is_empty() {
return Err(crate::error::Error::other(
"At least one valid sentinel node is required for sentinel connection",
));
}
Ok(Self::Sentinel {
master_name: master_name.to_string(),
sentinels: nodes,
redis_connection_info,
tls_certs: Some(tls_certs),
})
}
}
impl std::fmt::Debug for RedisConnectionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RedisConnectionType::Single {
connection_info, ..
} => {
#[cfg(feature = "tls")]
{
f.debug_struct("Single")
.field("connection_info", connection_info)
.field("tls_certs", &"<tls-certs>")
.finish()
}
#[cfg(not(feature = "tls"))]
{
f.debug_struct("Single")
.field("connection_info", connection_info)
.finish()
}
}
#[cfg(feature = "cluster")]
crate::backend::RedisConnectionType::Cluster(nodes) => {
f.debug_tuple("Cluster").field(nodes).finish()
}
#[cfg(feature = "sentinel")]
crate::backend::RedisConnectionType::Sentinel {
master_name,
sentinels,
redis_connection_info,
..
} => {
#[cfg(feature = "tls")]
{
f.debug_struct("Sentinel")
.field("master_name", master_name)
.field("sentinels", sentinels)
.field("redis_connection_info", redis_connection_info)
.field("tls_certs", &"<tls-certs>")
.finish()
}
#[cfg(not(feature = "tls"))]
{
f.debug_struct("Sentinel")
.field("master_name", master_name)
.field("sentinels", sentinels)
.field("redis_connection_info", redis_connection_info)
.finish()
}
}
}
}
}