use redis::AsyncCommands;
use redis::aio::{ConnectionLike, ConnectionManager, MultiplexedConnection};
use redis::cluster_async::ClusterConnection;
use crate::cache::{Cache, CacheError};
use crate::utils::DynFuture;
use crate::wrappers::types::users::User;
pub struct RedisCache {
connection: RedisConnection,
}
impl RedisCache {
pub fn new(connection: impl Into<RedisConnection>) -> Self {
Self {
connection: connection.into(),
}
}
}
#[derive(Clone)]
pub enum RedisConnection {
Cluster(ClusterConnection),
Manager(ConnectionManager),
Multiplexed(MultiplexedConnection),
}
impl From<ClusterConnection> for RedisConnection {
fn from(value: ClusterConnection) -> Self {
Self::Cluster(value)
}
}
impl From<ConnectionManager> for RedisConnection {
fn from(value: ConnectionManager) -> Self {
Self::Manager(value)
}
}
impl From<MultiplexedConnection> for RedisConnection {
fn from(value: MultiplexedConnection) -> Self {
Self::Multiplexed(value)
}
}
impl ConnectionLike for RedisConnection {
fn get_db(&self) -> i64 {
match self {
Self::Cluster(connection) => connection.get_db(),
Self::Manager(connection) => connection.get_db(),
Self::Multiplexed(connection) => connection.get_db(),
}
}
fn req_packed_command<'a>(
&'a mut self,
cmd: &'a redis::Cmd,
) -> redis::RedisFuture<'a, redis::Value> {
match self {
Self::Cluster(connection) => connection.req_packed_command(cmd),
Self::Manager(connection) => connection.req_packed_command(cmd),
Self::Multiplexed(connection) => connection.req_packed_command(cmd),
}
}
fn req_packed_commands<'a>(
&'a mut self,
cmd: &'a redis::Pipeline,
offset: usize,
count: usize,
) -> redis::RedisFuture<'a, Vec<redis::Value>> {
match self {
Self::Cluster(connection) => connection.req_packed_commands(cmd, offset, count),
Self::Manager(connection) => connection.req_packed_commands(cmd, offset, count),
Self::Multiplexed(connection) => connection.req_packed_commands(cmd, offset, count),
}
}
}
impl Cache for RedisCache {
fn set_user(&self, user: User) -> DynFuture<'_, Result<(), CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let raw = bitcode::encode(&user);
let _: () = conn.set(format!("user:id:{}", user.id), &raw).await?;
let _: () = conn.set(format!("user:name:{}", user.name), &raw).await?;
Ok(())
})
}
fn get_user_by_id(&self, user_id: u64) -> DynFuture<'_, Result<Option<User>, CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let key = format!("user:id:{user_id}");
let result: Option<Vec<u8>> = conn.get(key).await?;
if let Some(result) = result {
Ok(Some(bitcode::decode(&result)?))
} else {
Ok(None)
}
})
}
fn get_user_by_name(
&self,
user_name: String,
) -> DynFuture<'_, Result<Option<User>, CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let key = format!("user:name:{user_name}");
let result: Option<Vec<u8>> = conn.get(key).await?;
if let Some(result) = result {
Ok(Some(bitcode::decode(&result)?))
} else {
Ok(None)
}
})
}
}