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::members::Member;
use crate::wrappers::types::servers::Server;
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();
let get_user_by_name = self.get_user_by_name(user.name.clone());
Box::pin(async move {
let raw = bitcode::encode(&user);
if let Some(cached_user) = get_user_by_name.await?
&& user.name != cached_user.name
{
let _: () = conn.del(format!("user:name:{}", cached_user.name)).await?;
}
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)
}
})
}
fn set_server(&self, server: Server) -> DynFuture<'_, Result<(), CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let raw = bitcode::encode(&server);
let _: () = conn.set(format!("server:{}", server.id), &raw).await?;
Ok(())
})
}
fn del_server(&self, server_id: u64) -> DynFuture<'_, Result<(), CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let _: () = conn.del(format!("server:{server_id}")).await?;
Ok(())
})
}
fn get_server_by_id(
&self,
server_id: u64,
) -> DynFuture<'_, Result<Option<Server>, CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let key = format!("server:{server_id}");
let result: Option<Vec<u8>> = conn.get(key).await?;
if let Some(result) = result {
Ok(Some(bitcode::decode(&result)?))
} else {
Ok(None)
}
})
}
fn set_member(&self, server_id: u64, member: Member) -> DynFuture<'_, Result<(), CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let raw = bitcode::encode(&member);
let _: () = conn
.set(format!("member:{}:{}", server_id, member.id), &raw)
.await?;
Ok(())
})
}
fn del_member(&self, server_id: u64, member_id: u64) -> DynFuture<'_, Result<(), CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let _: () = conn.del(format!("member:{server_id}:{member_id}")).await?;
Ok(())
})
}
fn get_member_by_id(
&self,
server_id: u64,
member_id: u64,
) -> DynFuture<'_, Result<Option<Member>, CacheError>> {
let mut conn = self.connection.clone();
Box::pin(async move {
let key = format!("member:{server_id}:{member_id}");
let result: Option<Vec<u8>> = conn.get(key).await?;
if let Some(result) = result {
Ok(Some(bitcode::decode(&result)?))
} else {
Ok(None)
}
})
}
}