| use redis::AsyncCommands; |
| use std::sync::Arc; |
| use tokio::sync::Mutex; |
| use tracing::warn; |
|
|
| #[derive(Clone)] |
| pub struct CacheClient { |
| inner: Option<Arc<Mutex<redis::aio::ConnectionManager>>>, |
| } |
|
|
| impl CacheClient { |
| pub async fn new(redis_url: &str) -> Self { |
| if redis_url.is_empty() { |
| warn!("REDIS_URL not set \u{2014} cache disabled"); |
| return Self { inner: None }; |
| } |
| match redis::Client::open(redis_url) { |
| Ok(client) => match client.get_connection_manager().await { |
| Ok(conn) => { |
| tracing::info!("Redis connected"); |
| Self { inner: Some(Arc::new(Mutex::new(conn))) } |
| } |
| Err(e) => { |
| warn!("Redis connection failed (cache disabled): {e}"); |
| Self { inner: None } |
| } |
| }, |
| Err(e) => { |
| warn!("Redis URL invalid (cache disabled): {e}"); |
| Self { inner: None } |
| } |
| } |
| } |
|
|
| pub async fn get_string(&self, key: &str) -> Option<String> { |
| let inner = self.inner.as_ref()?; |
| let mut conn = inner.lock().await; |
| conn.get(key).await.ok() |
| } |
|
|
| pub async fn set_string(&self, key: &str, val: &str, ttl_secs: u64) { |
| let Some(inner) = &self.inner else { return }; |
| let mut conn = inner.lock().await; |
| let _ = conn.set_ex::<_, _, ()>(key, val, ttl_secs).await; |
| } |
|
|
| pub async fn get_json(&self, key: &str) -> Option<serde_json::Value> { |
| let s = self.get_string(key).await?; |
| serde_json::from_str(&s).ok() |
| } |
|
|
| pub async fn set_json(&self, key: &str, val: &serde_json::Value, ttl_secs: u64) { |
| if let Ok(s) = serde_json::to_string(val) { |
| self.set_string(key, &s, ttl_secs).await; |
| } |
| } |
|
|
| pub async fn del(&self, key: &str) { |
| let Some(inner) = &self.inner else { return }; |
| let mut conn = inner.lock().await; |
| let _ = conn.del::<_, ()>(key).await; |
| } |
|
|
| pub async fn del_pattern(&self, pattern: &str) { |
| let Some(inner) = &self.inner else { return }; |
| let mut conn = inner.lock().await; |
| let keys: Vec<String> = conn.keys(pattern).await.unwrap_or_default(); |
| if !keys.is_empty() { |
| let _ = conn.del::<_, ()>(keys).await; |
| } |
| } |
| } |
|
|