use async_trait::async_trait; use deadpool_redis::{Config, Pool, Runtime}; use redis::{AsyncCommands, RedisError}; use serde::{Deserialize, Serialize}; #[async_trait] pub trait Cache { async fn set(&self, key: &String, value: &T, ttl: u64) -> Result<(), redis::RedisError>; async fn update( &self, key: &String, value: Option<&T>, ttl: Option, ) -> Result<(), redis::RedisError>; async fn get serde::Deserialize<'de> + Send + Sync>( &self, key: &String, ) -> Result, redis::RedisError>; async fn delete(&mut self, key: &str) -> redis::RedisResult<()>; async fn refresh(&self, key: &str, ttl: i64) -> redis::RedisResult<()>; } pub struct RedisCache { pub pool: Pool, } impl RedisCache { pub fn new(redis_url: &str) -> Self { let cfg = Config::from_url(redis_url); let pool = cfg .create_pool(Some(Runtime::Tokio1)) .expect("Failed to create Redis pool"); RedisCache { pool } } } #[async_trait] impl Cache for RedisCache { async fn set( &self, key: &String, value: &T, ttl: u64, ) -> Result<(), redis::RedisError> { let mut conn = self.pool.get().await.map_err(|err| { redis::RedisError::from(( redis::ErrorKind::IoError, "Failed to get Redis connection", format!("{:?}", err), )) })?; let serialized_value = serde_json::to_string(value).map_err(|err| { RedisError::from(( redis::ErrorKind::IoError, "Serialization error", format!("Serialization error: {}", err), )) })?; if ttl > 0 { conn.set_ex(key, serialized_value, ttl).await } else { conn.set(key, serialized_value).await } } async fn get Deserialize<'de> + Send + Sync>( &self, key: &String, ) -> Result, redis::RedisError> { let mut conn = self.pool.get().await.map_err(|err| { redis::RedisError::from(( redis::ErrorKind::IoError, "Failed to get Redis connection", format!("{:?}", err), )) })?; if let Some(serialized_value) = conn.get::<_, Option>(key).await? { let deserialized_value = serde_json::from_str(&serialized_value).map_err(|err| { RedisError::from(( redis::ErrorKind::IoError, "Deserialization error", format!("Deserialization error: {}", err), )) })?; Ok(Some(deserialized_value)) } else { Ok(None) } } async fn update( &self, key: &String, value: Option<&T>, ttl: Option, ) -> Result<(), redis::RedisError> { let mut conn = self.pool.get().await.map_err(|err| { redis::RedisError::from(( redis::ErrorKind::IoError, "Failed to get Redis connection", format!("{:?}", err), )) })?; let serialized_value; if value.is_some() { serialized_value = serde_json::to_string(&value).map_err(|err| { RedisError::from(( redis::ErrorKind::IoError, "Serialization error", format!("Serialization error: {}", err), )) })?; } else { serialized_value = conn.get(key).await?; } if ttl != None { conn.set_ex(key, serialized_value, ttl.unwrap()).await } else { conn.set(key, serialized_value).await } } async fn delete(&mut self, key: &str) -> redis::RedisResult<()> { let mut conn = self.pool.get().await.map_err(|err| { redis::RedisError::from(( redis::ErrorKind::IoError, "Failed to get Redis connection", format!("{:?}", err), )) })?; conn.del(key).await } async fn refresh(&self, key: &str, ttl: i64) -> redis::RedisResult<()> { let mut conn = self.pool.get().await.map_err(|err| { redis::RedisError::from(( redis::ErrorKind::IoError, "Failed to get Redis connection", format!("{:?}", err), )) })?; conn.expire(key, ttl).await } }