use async_trait::async_trait; use deadpool_redis::{Config, Pool, Runtime}; use redis::{AsyncCommands, Commands, 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<()>; } 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 } }