use crate::{
clients::{Pipeline, WithOptions},
commands,
error::{RedisError, RedisErrorKind},
interfaces::*,
modules::inner::RedisClientInner,
prelude::ClientLike,
runtime::RefCount,
types::*,
};
use bytes_utils::Str;
use futures::Stream;
use std::{fmt, fmt::Formatter};
#[cfg(feature = "replicas")]
use crate::clients::Replicas;
#[cfg(feature = "i-tracking")]
use crate::interfaces::TrackingInterface;
#[derive(Clone)]
pub struct RedisClient {
pub(crate) inner: RefCount<RedisClientInner>,
}
impl Default for RedisClient {
fn default() -> Self {
RedisClient::new(RedisConfig::default(), None, None, None)
}
}
impl fmt::Debug for RedisClient {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RedisClient")
.field("id", &self.inner.id)
.field("state", &self.state())
.finish()
}
}
impl fmt::Display for RedisClient {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.inner.id)
}
}
#[doc(hidden)]
impl<'a> From<&'a RefCount<RedisClientInner>> for RedisClient {
fn from(inner: &'a RefCount<RedisClientInner>) -> RedisClient {
RedisClient { inner: inner.clone() }
}
}
impl ClientLike for RedisClient {
#[doc(hidden)]
fn inner(&self) -> &RefCount<RedisClientInner> {
&self.inner
}
}
impl EventInterface for RedisClient {}
#[cfg(feature = "i-redis-json")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-redis-json")))]
impl RedisJsonInterface for RedisClient {}
#[cfg(feature = "i-time-series")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-time-series")))]
impl TimeSeriesInterface for RedisClient {}
#[cfg(feature = "i-acl")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-acl")))]
impl AclInterface for RedisClient {}
#[cfg(feature = "i-client")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-client")))]
impl ClientInterface for RedisClient {}
#[cfg(feature = "i-cluster")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-cluster")))]
impl ClusterInterface for RedisClient {}
#[cfg(feature = "i-config")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-config")))]
impl ConfigInterface for RedisClient {}
#[cfg(feature = "i-geo")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-geo")))]
impl GeoInterface for RedisClient {}
#[cfg(feature = "i-hashes")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-hashes")))]
impl HashesInterface for RedisClient {}
#[cfg(feature = "i-hyperloglog")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-hyperloglog")))]
impl HyperloglogInterface for RedisClient {}
impl MetricsInterface for RedisClient {}
#[cfg(feature = "transactions")]
#[cfg_attr(docsrs, doc(cfg(feature = "transactions")))]
impl TransactionInterface for RedisClient {}
#[cfg(feature = "i-keys")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-keys")))]
impl KeysInterface for RedisClient {}
#[cfg(feature = "i-scripts")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-scripts")))]
impl LuaInterface for RedisClient {}
#[cfg(feature = "i-lists")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-lists")))]
impl ListInterface for RedisClient {}
#[cfg(feature = "i-memory")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-memory")))]
impl MemoryInterface for RedisClient {}
impl AuthInterface for RedisClient {}
#[cfg(feature = "i-server")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-server")))]
impl ServerInterface for RedisClient {}
#[cfg(feature = "i-slowlog")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-slowlog")))]
impl SlowlogInterface for RedisClient {}
#[cfg(feature = "i-sets")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-sets")))]
impl SetsInterface for RedisClient {}
#[cfg(feature = "i-sorted-sets")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-sorted-sets")))]
impl SortedSetsInterface for RedisClient {}
#[cfg(feature = "i-server")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-server")))]
impl HeartbeatInterface for RedisClient {}
#[cfg(feature = "i-streams")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-streams")))]
impl StreamsInterface for RedisClient {}
#[cfg(feature = "i-scripts")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-scripts")))]
impl FunctionInterface for RedisClient {}
#[cfg(feature = "i-tracking")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-tracking")))]
impl TrackingInterface for RedisClient {}
#[cfg(feature = "i-pubsub")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-pubsub")))]
impl PubsubInterface for RedisClient {}
#[cfg(feature = "i-redisearch")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-redisearch")))]
impl RediSearchInterface for RedisClient {}
impl RedisClient {
pub fn new(
config: RedisConfig,
perf: Option<PerformanceConfig>,
connection: Option<ConnectionConfig>,
policy: Option<ReconnectPolicy>,
) -> RedisClient {
RedisClient {
inner: RedisClientInner::new(config, perf.unwrap_or_default(), connection.unwrap_or_default(), policy),
}
}
pub fn clone_new(&self) -> Self {
let mut policy = self.inner.policy.read().clone();
if let Some(policy) = policy.as_mut() {
policy.reset_attempts();
}
RedisClient::new(
self.inner.config.as_ref().clone(),
Some(self.inner.performance_config()),
Some(self.inner.connection_config()),
policy,
)
}
pub fn split_cluster(&self) -> Result<Vec<RedisClient>, RedisError> {
if self.inner.config.server.is_clustered() {
commands::server::split(&self.inner)
} else {
Err(RedisError::new(
RedisErrorKind::Unknown,
"Client is not using a clustered deployment.",
))
}
}
pub fn scan<P>(
&self,
pattern: P,
count: Option<u32>,
r#type: Option<ScanType>,
) -> impl Stream<Item = Result<ScanResult, RedisError>>
where
P: Into<Str>,
{
commands::scan::scan(&self.inner, pattern.into(), count, r#type, None)
}
pub fn scan_cluster<P>(
&self,
pattern: P,
count: Option<u32>,
r#type: Option<ScanType>,
) -> impl Stream<Item = Result<ScanResult, RedisError>>
where
P: Into<Str>,
{
commands::scan::scan_cluster(&self.inner, pattern.into(), count, r#type)
}
pub fn hscan<K, P>(
&self,
key: K,
pattern: P,
count: Option<u32>,
) -> impl Stream<Item = Result<HScanResult, RedisError>>
where
K: Into<RedisKey>,
P: Into<Str>,
{
commands::scan::hscan(&self.inner, key.into(), pattern.into(), count)
}
pub fn sscan<K, P>(
&self,
key: K,
pattern: P,
count: Option<u32>,
) -> impl Stream<Item = Result<SScanResult, RedisError>>
where
K: Into<RedisKey>,
P: Into<Str>,
{
commands::scan::sscan(&self.inner, key.into(), pattern.into(), count)
}
pub fn zscan<K, P>(
&self,
key: K,
pattern: P,
count: Option<u32>,
) -> impl Stream<Item = Result<ZScanResult, RedisError>>
where
K: Into<RedisKey>,
P: Into<Str>,
{
commands::scan::zscan(&self.inner, key.into(), pattern.into(), count)
}
pub fn pipeline(&self) -> Pipeline<RedisClient> {
Pipeline::from(self.clone())
}
pub fn with_cluster_node<S>(&self, server: S) -> WithOptions<Self>
where
S: Into<Server>,
{
WithOptions {
client: self.clone(),
options: Options {
cluster_node: Some(server.into()),
..Default::default()
},
}
}
#[cfg(feature = "replicas")]
#[cfg_attr(docsrs, doc(cfg(feature = "replicas")))]
pub fn replicas(&self) -> Replicas {
Replicas::from(&self.inner)
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "sha-1")]
use crate::util;
#[test]
#[cfg(feature = "sha-1")]
fn should_correctly_sha1_hash() {
assert_eq!(
&util::sha1_hash("foobarbaz"),
"5f5513f8822fdbe5145af33b64d8d970dcf95c6e"
);
assert_eq!(&util::sha1_hash("abc123"), "6367c48dd193d56ea7b0baad25b19455e529f5ee");
assert_eq!(
&util::sha1_hash("jakdjfkldajfklej8a4tjkaldsnvkl43kjakljdvk42"),
"45c118f5de7c3fd3a4022135dc6acfb526f3c225"
);
}
}