use std::time::SystemTime; use redis::{AsyncCommands, RedisResult, aio::ConnectionManager}; use serde::{Deserialize, Serialize, de::DeserializeOwned}; use tokio::sync::OnceCell; static REDIS_MANAGER: OnceCell = OnceCell::const_new(); pub const FRESH_SECONDS: u64 = 300; pub const STALE_SECONDS: u64 = 900; pub async fn get_redis_manager() -> ConnectionManager { REDIS_MANAGER.get_or_init(|| async { let client = redis::Client::open("redis://127.0.0.1:6379").expect("Failed to initialize redis client"); ConnectionManager::new(client).await.expect("Failed to initialize redis Connection Manager") }).await.clone() } #[derive(Serialize, Deserialize)] pub struct Cached { pub value: T, pub fetched_at: u64, } pub fn now_unix() -> u64 { SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("system clock is before 1970") .as_secs() } pub async fn cache_get(key: &str) -> RedisResult>> { let raw: Option = get_redis_manager().await.get(key).await?; Ok(raw.and_then(|s| serde_json::from_str(&s).ok())) } pub async fn cache_set(key: &str, value: &T) -> RedisResult<()> { let entry = Cached { value, fetched_at: now_unix() }; let raw = serde_json::to_string(&entry).expect("Failed to serialize cache entry"); let _: () = get_redis_manager().await.set_ex(key, raw, STALE_SECONDS).await?; Ok(()) }