Skip to main content

karbon_framework/cache/
memory_cache.rs

1use serde::{de::DeserializeOwned, Serialize};
2use std::collections::HashMap;
3use std::sync::Arc;
4use std::time::{Duration, Instant};
5use tokio::sync::RwLock;
6
7/// Simple in-memory cache with TTL support
8///
9/// For production, swap this with a Redis-backed implementation.
10#[derive(Clone)]
11pub struct Cache {
12    store: Arc<RwLock<HashMap<String, CacheEntry>>>,
13    default_ttl: Duration,
14}
15
16struct CacheEntry {
17    data: String, // JSON serialized
18    expires_at: Instant,
19}
20
21impl Cache {
22    /// Create a new cache with a default TTL
23    pub fn new(default_ttl: Duration) -> Self {
24        Self {
25            store: Arc::new(RwLock::new(HashMap::new())),
26            default_ttl,
27        }
28    }
29
30    /// Create with 5 minute default TTL
31    pub fn default_five_min() -> Self {
32        Self::new(Duration::from_secs(300))
33    }
34
35    /// Get a value from cache
36    pub async fn get<T: DeserializeOwned>(&self, key: &str) -> Option<T> {
37        let store = self.store.read().await;
38        let entry = store.get(key)?;
39
40        if Instant::now() > entry.expires_at {
41            return None;
42        }
43
44        serde_json::from_str(&entry.data).ok()
45    }
46
47    /// Set a value with default TTL
48    pub async fn set<T: Serialize>(&self, key: &str, value: &T) {
49        self.set_with_ttl(key, value, self.default_ttl).await;
50    }
51
52    /// Set a value with a custom TTL
53    pub async fn set_with_ttl<T: Serialize>(&self, key: &str, value: &T, ttl: Duration) {
54        if let Ok(data) = serde_json::to_string(value) {
55            let mut store = self.store.write().await;
56            store.insert(
57                key.to_string(),
58                CacheEntry {
59                    data,
60                    expires_at: Instant::now() + ttl,
61                },
62            );
63        }
64    }
65
66    /// Remove a value from cache
67    pub async fn remove(&self, key: &str) {
68        let mut store = self.store.write().await;
69        store.remove(key);
70    }
71
72    /// Clear all expired entries
73    pub async fn cleanup(&self) {
74        let mut store = self.store.write().await;
75        let now = Instant::now();
76        store.retain(|_, entry| entry.expires_at > now);
77    }
78
79    /// Clear the entire cache
80    pub async fn clear(&self) {
81        let mut store = self.store.write().await;
82        store.clear();
83    }
84}