1use std::time::{Duration, Instant};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum Alive {
13 Yes,
15 Ping,
17 Dead(Duration),
19}
20
21#[derive(Clone, Debug)]
23pub struct Liveness {
24 interval: Duration,
25 timeout: Duration,
26 last_heard: Instant,
27 last_ping: Option<Instant>,
28}
29
30impl Liveness {
31 pub fn new(interval: Duration, timeout: Duration, now: Instant) -> Liveness {
33 Liveness {
34 interval,
35 timeout,
36 last_heard: now,
37 last_ping: None,
38 }
39 }
40
41 pub fn heard(&mut self, now: Instant) {
43 self.last_heard = self.last_heard.max(now);
44 }
45
46 pub fn check(&mut self, now: Instant, may_ping: bool) -> Alive {
48 let silence = now.saturating_duration_since(self.last_heard);
49 if silence >= self.timeout {
50 return Alive::Dead(silence);
51 }
52 if may_ping && silence >= self.interval && now >= self.next_ping() {
53 self.last_ping = Some(now);
54 return Alive::Ping;
55 }
56 Alive::Yes
57 }
58
59 pub fn next_check(&self, may_ping: bool) -> Instant {
61 let dead_at = self.last_heard + self.timeout;
62 if may_ping {
63 dead_at.min(self.next_ping())
64 } else {
65 dead_at
66 }
67 }
68
69 fn next_ping(&self) -> Instant {
71 let since = match self.last_ping {
72 Some(ping) if ping > self.last_heard => ping,
73 _ => self.last_heard,
74 };
75 since + self.interval
76 }
77}