use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use std::thread;
#[derive(Debug, Clone)]
struct ExpiringValue {
value: String,
expires_at: Option<Instant>,
}
#[derive(Debug, Clone)]
pub struct InMemoryDB {
store: Arc<Mutex<HashMap<String, ExpiringValue>>>,
}
impl InMemoryDB {
pub fn new() -> Self {
InMemoryDB {
store: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn set(&self, key: String, value: String, ttl: Option<Duration>) {
let expires_at = ttl.map(|duration| Instant::now() + duration);
let expiring_value = ExpiringValue { value, expires_at };
self.store.lock().unwrap().insert(key, expiring_value);
}
pub fn get(&self, key: &str) -> Option<String> {
let mut store = self.store.lock().unwrap();
if let Some(expiring_value) = store.get(key) {
if let Some(expires_at) = expiring_value.expires_at {
if Instant::now() >= expires_at {
log::info!("Key '{}' has expired", key);
store.remove(key); return None;
}
}
return Some(expiring_value.value.clone());
}
None
}
pub fn delete(&self, key: &str) -> bool {
self.store.lock().unwrap().remove(key).is_some()
}
pub fn start_expiration_thread(&self) {
let store = Arc::clone(&self.store);
thread::spawn(move || loop {
thread::sleep(Duration::from_secs(1));
let mut store = store.lock().unwrap();
let now = Instant::now();
store.retain(|key, v| {
if let Some(expiration) = v.expires_at {
if expiration <= now {
log::info!("Key '{}' expired and removed", key);
return false; }
}
true });
});
}
}