use std::time::Duration;
use redis::AsyncCommands;
use serde::{Deserialize, Serialize};
use crate::cache::{HttpCacheKey, HttpCacheStorage};
#[derive(Clone)]
pub enum RedisClient {
Single(redis::aio::ConnectionManager),
Cluster(redis::cluster_async::ClusterConnection),
}
impl std::fmt::Debug for RedisClient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Single(_) => write!(f, "Single"),
Self::Cluster(_) => write!(f, "Cluster"),
}
}
}
pub struct HttpCacheRedis {
cache_ttl: Duration,
prefix: Option<Vec<u8>>,
client: RedisClient,
}
impl std::fmt::Debug for HttpCacheRedis {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HttpCacheRedis")
.field("cache_ttl", &self.cache_ttl)
.field("prefix", &self.prefix)
.field("client", &self.client)
.finish_non_exhaustive()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Config {
pub key_prefix: Option<String>,
#[serde(default)]
pub connection_string: String,
#[serde(default)]
pub use_cluster: bool,
pub cluster_nodes: Option<Vec<String>>,
}
impl HttpCacheRedis {
pub fn new(client: RedisClient) -> Self {
Self {
client,
prefix: None,
cache_ttl: Duration::from_secs(60),
}
}
pub fn set_prefix(mut self, prefix: Vec<u8>) -> Self {
self.prefix = Some(prefix);
self
}
}
#[async_trait::async_trait]
impl HttpCacheStorage for HttpCacheRedis {
fn set_expiration_times(&mut self, cache_ttl: Duration, _cache_tti: Duration) {
self.cache_ttl = cache_ttl;
}
async fn get(&self, key: &HttpCacheKey) -> Option<Vec<u8>> {
let mut db_key = self.prefix.clone().unwrap_or_default();
db_key.extend(&**key);
match &self.client {
RedisClient::Single(conn) => conn
.clone()
.get(db_key)
.await
.map_err(|err| {
tracing::error!("Failed to get value from redis: {}", err);
err
})
.ok()?,
RedisClient::Cluster(conn) => conn
.clone()
.get(db_key)
.await
.map_err(|err| {
tracing::error!("Failed to get value from redis cluster: {}", err);
err
})
.ok()?,
}
}
async fn set(&self, key: HttpCacheKey, value: Vec<u8>) {
let mut db_key = self.prefix.clone().unwrap_or_default();
db_key.extend(&*key);
match &self.client {
RedisClient::Single(conn) => {
let _: Result<(), _> = conn
.clone()
.set_ex(db_key, value, self.cache_ttl.as_secs())
.await
.map_err(|err| {
tracing::error!("Failed to set value in redis: {}", err);
err
});
}
RedisClient::Cluster(conn) => {
let _: Result<(), _> = conn
.clone()
.set_ex(db_key, value, self.cache_ttl.as_secs())
.await
.map_err(|err| {
tracing::error!("Failed to set value in redis cluster: {}", err);
err
});
}
}
}
}