use std::{
sync::{Mutex, TryLockError},
time::Instant,
};
use super::*;
pub const CACHED_ADDRS_REFRESH_INTERVAL: Duration = Duration::from_secs(10 * 60);
pub struct CachedPeerAddrResponse {
address_book: Arc<Mutex<zn::AddressBook>>,
value: zn::Response,
refresh_time: Instant,
}
impl CachedPeerAddrResponse {
pub(super) fn new(address_book: Arc<Mutex<AddressBook>>) -> Self {
Self {
address_book,
value: zn::Response::Nil,
refresh_time: Instant::now(),
}
}
pub(super) fn value(&self) -> zn::Response {
self.value.clone()
}
pub(super) fn try_refresh(&mut self) {
let now = Instant::now();
if now < self.refresh_time {
return;
}
let cache_expiry = self.refresh_time + CACHED_ADDRS_REFRESH_INTERVAL;
match self
.address_book
.try_lock()
.map(|book| book.fresh_get_addr_response())
{
Ok(peers) if !peers.is_empty() => {
self.refresh_time = now + CACHED_ADDRS_REFRESH_INTERVAL;
self.value = zn::Response::Peers(peers);
}
Ok(_) if now > cache_expiry => {
self.value = zn::Response::Nil;
}
Err(TryLockError::WouldBlock) if now > cache_expiry => {
warn!("getaddrs response hasn't been refreshed in some time");
self.value = zn::Response::Nil;
}
Ok(_) => {
debug!(
"could not refresh cached response because our address \
book has no available peers"
);
}
Err(TryLockError::WouldBlock) => {}
Err(TryLockError::Poisoned(_)) => {
panic!("previous thread panicked while holding the address book lock")
}
};
}
}