use dyn_clone::DynClone;
use lru::LruCache;
use std::fmt::Debug;
use std::num::NonZeroUsize;
use std::sync::{Arc, RwLock};
use crate::SignedPacket;
pub type CacheKey = [u8; 20];
impl From<&crate::PublicKey> for CacheKey {
fn from(public_key: &crate::PublicKey) -> CacheKey {
let mut encoded = vec![];
encoded.extend(public_key.as_bytes());
let mut hasher = sha1_smol::Sha1::new();
hasher.update(&encoded);
hasher.digest().bytes()
}
}
impl From<crate::PublicKey> for CacheKey {
fn from(value: crate::PublicKey) -> Self {
(&value).into()
}
}
pub trait Cache: Debug + Send + Sync + DynClone {
fn capacity(&self) -> usize {
0
}
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn put(&self, key: &CacheKey, signed_packet: &SignedPacket);
fn get(&self, key: &CacheKey) -> Option<SignedPacket>;
fn get_read_only(&self, key: &CacheKey) -> Option<SignedPacket> {
self.get(key)
}
}
dyn_clone::clone_trait_object!(Cache);
#[derive(Debug, Clone)]
pub struct InMemoryCache {
inner: Arc<RwLock<LruCache<CacheKey, SignedPacket>>>,
}
impl InMemoryCache {
pub fn new(capacity: NonZeroUsize) -> Self {
Self {
inner: Arc::new(RwLock::new(LruCache::new(capacity))),
}
}
}
impl Cache for InMemoryCache {
fn capacity(&self) -> usize {
self.inner
.read()
.expect("InMemoryCache RwLock")
.cap()
.into()
}
fn len(&self) -> usize {
self.inner.read().expect("InMemoryCache RwLock").len()
}
fn put(&self, key: &CacheKey, signed_packet: &SignedPacket) {
let mut lock = self.inner.write().expect("InMemoryCache RwLock");
match lock.get_mut(key) {
Some(existing) => {
if existing.as_bytes() == signed_packet.as_bytes() {
existing.set_last_seen(signed_packet.last_seen())
} else {
lock.put(*key, signed_packet.clone());
}
}
None => {
lock.put(*key, signed_packet.clone());
}
}
}
fn get(&self, key: &CacheKey) -> Option<SignedPacket> {
self.inner
.write()
.expect("InMemoryCache RwLock")
.get(key)
.cloned()
}
fn get_read_only(&self, key: &CacheKey) -> Option<SignedPacket> {
self.inner
.read()
.expect("InMemoryCache RwLock")
.peek(key)
.cloned()
}
}