1use dyn_clone::DynClone;
4use lru::LruCache;
5use std::fmt::Debug;
6use std::num::NonZeroUsize;
7use std::sync::{Arc, RwLock};
8
9use crate::SignedPacket;
10
11pub type CacheKey = [u8; 20];
13
14impl From<&crate::PublicKey> for CacheKey {
15 fn from(public_key: &crate::PublicKey) -> CacheKey {
16 let mut encoded = vec![];
17
18 encoded.extend(public_key.as_bytes());
19
20 let mut hasher = sha1_smol::Sha1::new();
21 hasher.update(&encoded);
22 hasher.digest().bytes()
23 }
24}
25
26impl From<crate::PublicKey> for CacheKey {
27 fn from(value: crate::PublicKey) -> Self {
28 (&value).into()
29 }
30}
31
32pub trait Cache: Debug + Send + Sync + DynClone {
34 fn capacity(&self) -> usize {
36 0
38 }
39 fn len(&self) -> usize;
41 fn is_empty(&self) -> bool {
43 self.len() == 0
44 }
45 fn put(&self, key: &CacheKey, signed_packet: &SignedPacket);
47 fn get(&self, key: &CacheKey) -> Option<SignedPacket>;
49 fn get_read_only(&self, key: &CacheKey) -> Option<SignedPacket> {
59 self.get(key)
60 }
61}
62
63dyn_clone::clone_trait_object!(Cache);
64
65#[derive(Debug, Clone)]
67pub struct InMemoryCache {
68 inner: Arc<RwLock<LruCache<CacheKey, SignedPacket>>>,
69}
70
71impl InMemoryCache {
72 pub fn new(capacity: NonZeroUsize) -> Self {
74 Self {
75 inner: Arc::new(RwLock::new(LruCache::new(capacity))),
76 }
77 }
78}
79
80impl Cache for InMemoryCache {
81 fn capacity(&self) -> usize {
82 self.inner
83 .read()
84 .expect("InMemoryCache RwLock")
85 .cap()
86 .into()
87 }
88
89 fn len(&self) -> usize {
90 self.inner.read().expect("InMemoryCache RwLock").len()
91 }
92
93 fn put(&self, key: &CacheKey, signed_packet: &SignedPacket) {
97 let mut lock = self.inner.write().expect("InMemoryCache RwLock");
98
99 match lock.get_mut(key) {
100 Some(existing) => {
101 if existing.as_bytes() == signed_packet.as_bytes() {
102 existing.set_last_seen(signed_packet.last_seen())
104 } else {
105 lock.put(*key, signed_packet.clone());
106 }
107 }
108 None => {
109 lock.put(*key, signed_packet.clone());
110 }
111 }
112 }
113
114 fn get(&self, key: &CacheKey) -> Option<SignedPacket> {
115 self.inner
116 .write()
117 .expect("InMemoryCache RwLock")
118 .get(key)
119 .cloned()
120 }
121
122 fn get_read_only(&self, key: &CacheKey) -> Option<SignedPacket> {
123 self.inner
124 .read()
125 .expect("InMemoryCache RwLock")
126 .peek(key)
127 .cloned()
128 }
129}