use crate::utils::system::safe_system_time;
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
static MEMORY_CACHE: Lazy<Arc<Mutex<MemoryCache>>> =
Lazy::new(|| Arc::new(Mutex::new(MemoryCache::new())));
#[derive(Clone)]
struct CachedItem {
content: String,
timestamp: SystemTime,
}
struct MemoryCache {
cache: HashMap<String, CachedItem>,
}
impl MemoryCache {
fn new() -> Self {
Self {
cache: HashMap::new(),
}
}
}
pub fn store(key: &str, content: &str) -> Result<(), String> {
let mut cache = match MEMORY_CACHE.lock() {
Ok(cache) => cache,
Err(e) => return Err(format!("Failed to lock memory cache: {}", e)),
};
cache.cache.insert(
key.to_string(),
CachedItem {
content: content.to_string(),
timestamp: safe_system_time(),
},
);
Ok(())
}
pub fn get(key: &str) -> Option<String> {
let cache = match MEMORY_CACHE.lock() {
Ok(cache) => cache,
Err(_) => return None,
};
cache.cache.get(key).map(|item| item.content.clone())
}
pub fn exists(key: &str) -> bool {
let cache = match MEMORY_CACHE.lock() {
Ok(cache) => cache,
Err(_) => return false,
};
cache.cache.contains_key(key)
}
pub fn is_valid(key: &str, max_age: u32) -> bool {
let cache = match MEMORY_CACHE.lock() {
Ok(cache) => cache,
Err(_) => return false,
};
if let Some(item) = cache.cache.get(key) {
let now = safe_system_time();
if let Ok(elapsed) = now.duration_since(item.timestamp) {
return elapsed.as_secs() < u64::from(max_age);
}
}
false
}
pub fn get_if_valid(key: &str, max_age: u32) -> Option<String> {
let cache = match MEMORY_CACHE.lock() {
Ok(cache) => cache,
Err(_) => return None,
};
if let Some(item) = cache.cache.get(key) {
let now = safe_system_time();
if let Ok(elapsed) = now.duration_since(item.timestamp) {
if elapsed.as_secs() < u64::from(max_age) {
return Some(item.content.clone());
}
}
}
None
}
pub fn remove(key: &str) {
if let Ok(mut cache) = MEMORY_CACHE.lock() {
cache.cache.remove(key);
}
}
pub fn clear() {
if let Ok(mut cache) = MEMORY_CACHE.lock() {
cache.cache.clear();
}
}
pub fn size() -> usize {
if let Ok(cache) = MEMORY_CACHE.lock() {
return cache.cache.len();
}
0
}
pub fn clean_expired(max_age: u32) {
if let Ok(mut cache) = MEMORY_CACHE.lock() {
let now = safe_system_time();
let max_duration = Duration::from_secs(u64::from(max_age));
cache.cache.retain(|_, item| {
if let Ok(elapsed) = now.duration_since(item.timestamp) {
elapsed <= max_duration
} else {
true
}
});
}
}