use std::time::{Duration, Instant};
use super::DISCOVER_INTERVAL;
pub(super) const HELLO_BASE: Duration = Duration::from_millis(2500);
pub(super) const HELLO_JITTER: Duration = Duration::from_millis(2500);
pub(super) fn next_hello_interval() -> Duration {
let mut bytes = [0u8; 2];
if getrandom::getrandom(&mut bytes).is_err() {
return HELLO_BASE + HELLO_JITTER / 2;
}
let fraction = u64::from(u16::from_be_bytes(bytes));
let jitter = HELLO_JITTER.as_nanos().saturating_mul(u128::from(fraction)) / 65536;
HELLO_BASE + Duration::from_nanos(jitter as u64)
}
#[derive(Debug)]
pub(super) struct Schedule {
last_hello: Option<Instant>,
hello_interval: Duration,
last_discover: Option<Instant>,
}
impl Schedule {
pub(super) fn new() -> Self {
Self {
last_hello: None,
hello_interval: next_hello_interval(),
last_discover: None,
}
}
pub(super) fn announce_due(&self, now: Instant) -> bool {
self.last_hello.map_or(true, |last| {
now.saturating_duration_since(last) >= self.hello_interval
})
}
pub(super) fn announced(&mut self, now: Instant) {
self.last_hello = Some(now);
self.hello_interval = next_hello_interval();
}
pub(super) fn discover_due(&self, now: Instant) -> bool {
self.last_discover.map_or(true, |last| {
now.saturating_duration_since(last) >= DISCOVER_INTERVAL
})
}
pub(super) fn discovered(&mut self, now: Instant) {
self.last_discover = Some(now);
}
#[cfg(test)]
pub(super) fn hello_timer(&self) -> (Option<Instant>, Duration) {
(self.last_hello, self.hello_interval)
}
#[cfg(test)]
pub(super) fn set_hello_timer(&mut self, last: Option<Instant>, interval: Duration) {
self.last_hello = last;
self.hello_interval = interval;
}
}