Something went wrong. Try again.
Microservice to bring 2FA to self hosted PDSes
Something went wrong. Try again.
2.6 kB · 101 lines
Rust
at sendmail
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102use dashmap::DashMap;use std::sync::Arc;use std::time::{Duration, Instant};
#[derive(Clone, Debug)]struct CachedHandle { handle: String, cached_at: Instant,}
/// A thread-safe cache for DID-to-handle resolutions with TTL expiration.#[derive(Clone)]pub struct HandleCache { cache: Arc<DashMap<String, CachedHandle>>, ttl: Duration,}
impl Default for HandleCache { fn default() -> Self { Self::new() }}
impl HandleCache { /// Creates a new HandleCache with a default TTL of 1 hour. pub fn new() -> Self { Self::with_ttl(Duration::from_secs(3600)) }
/// Creates a new HandleCache with a custom TTL. pub fn with_ttl(ttl: Duration) -> Self { Self { cache: Arc::new(DashMap::new()), ttl, } }
/// Gets a cached handle for the given DID, if it exists and hasn't expired. pub fn get(&self, did: &str) -> Option<String> { let entry = self.cache.get(did)?; if entry.cached_at.elapsed() > self.ttl { drop(entry); self.cache.remove(did); return None; } Some(entry.handle.clone()) }
/// Inserts a DID-to-handle mapping into the cache. pub fn insert(&self, did: String, handle: String) { self.cache.insert( did, CachedHandle { handle, cached_at: Instant::now(), }, ); }
/// Removes expired entries from the cache. /// Call this periodically to prevent memory growth. pub fn cleanup(&self) { self.cache.retain(|_, v| v.cached_at.elapsed() <= self.ttl); }
/// Returns the number of entries in the cache. pub fn len(&self) -> usize { self.cache.len() }
/// Returns true if the cache is empty. pub fn is_empty(&self) -> bool { self.cache.is_empty() }}
#[cfg(test)]mod tests { use super::*;
#[test] fn test_cache_insert_and_get() { let cache = HandleCache::new(); cache.insert("did:plc:test".into(), "test.handle.com".into()); assert_eq!(cache.get("did:plc:test"), Some("test.handle.com".into())); }
#[test] fn test_cache_miss() { let cache = HandleCache::new(); assert_eq!(cache.get("did:plc:nonexistent"), None); }
#[test] fn test_cache_expiration() { let cache = HandleCache::with_ttl(Duration::from_millis(1)); cache.insert("did:plc:test".into(), "test.handle.com".into()); std::thread::sleep(Duration::from_millis(10)); assert_eq!(cache.get("did:plc:test"), None); }}