1use std::{
2 num::NonZeroUsize,
3 sync::{Arc, Mutex},
4};
5
6use iroh_base::PublicKey;
7
8type SignatureError = <PublicKey as TryFrom<&'static [u8]>>::Error;
9type PublicKeyBytes = [u8; PublicKey::LENGTH];
10
11#[derive(Debug, Clone)]
19pub enum KeyCache {
20 Disabled,
22 Shared(Arc<Mutex<lru::LruCache<PublicKey, ()>>>),
25}
26
27impl KeyCache {
28 #[cfg(all(test, feature = "server"))]
30 pub fn test() -> Self {
31 Self::Disabled
32 }
33
34 pub fn new(capacity: usize) -> Self {
38 let Some(capacity) = NonZeroUsize::new(capacity) else {
39 return Self::Disabled;
40 };
41 let cache = lru::LruCache::new(capacity);
42 Self::Shared(Arc::new(Mutex::new(cache)))
43 }
44
45 pub fn key_from_slice(&self, slice: &[u8]) -> Result<PublicKey, SignatureError> {
47 let Self::Shared(cache) = self else {
48 return PublicKey::try_from(slice);
49 };
50 let Ok(bytes) = PublicKeyBytes::try_from(slice) else {
51 return Err(PublicKey::try_from(slice).expect_err("invalid length"));
54 };
55 let mut cache = cache.lock().expect("not poisoned");
56 if let Some((key, _)) = cache.get_key_value(&bytes) {
57 return Ok(*key);
58 }
59 let key = PublicKey::from_bytes(&bytes)?;
60 cache.put(key, ());
61 Ok(key)
62 }
63}