krabka_raft/handshake/
stream.rs1use {
5 crate::{ObservedStream, StreamObserver},
6 std::{
7 io,
8 pin::pin,
9 sync::{
10 Arc, Mutex, PoisonError,
11 atomic::{AtomicBool, Ordering},
12 },
13 task::{Context, Poll},
14 time::Duration,
15 },
16 tokio::{
17 net::TcpStream,
18 time::{self, Instant},
19 },
20};
21
22pub type HandshakeStream<S = TcpStream> = ObservedStream<S, HandshakeClock>;
31
32pub struct HandshakeClock(Option<Arc<ActivityClock>>);
35
36impl HandshakeClock {
37 fn progressed(&self) {
38 if let Some(clock) = &self.0 {
39 clock.progressed();
40 }
41 }
42}
43
44impl StreamObserver for HandshakeClock {
45 fn on_read(&mut self, filled: usize) {
46 if filled > 0 {
47 self.progressed();
48 }
49 }
50
51 fn on_write(
52 &mut self,
53 _cx: &mut Context<'_>,
54 result: Poll<io::Result<usize>>,
55 ) -> Poll<io::Result<usize>> {
56 if matches!(result, Poll::Ready(Ok(written)) if written > 0) {
57 self.progressed();
58 }
59 result
60 }
61}
62
63impl<S> HandshakeStream<S> {
64 pub(crate) fn watched(inner: S, window: Duration) -> (Self, IdleWatch) {
67 let clock = Arc::new(ActivityClock {
68 armed: AtomicBool::new(true),
69 last_progress: Mutex::new(Instant::now()),
70 });
71 let watch = IdleWatch {
72 clock: Arc::clone(&clock),
73 window,
74 };
75 (Self::new(inner, HandshakeClock(Some(clock))), watch)
76 }
77}
78
79impl<S> From<S> for HandshakeStream<S> {
82 fn from(inner: S) -> Self { Self::new(inner, HandshakeClock(None)) }
83}
84
85struct ActivityClock {
87 armed: AtomicBool,
88 last_progress: Mutex<Instant>,
89}
90
91impl ActivityClock {
92 fn progressed(&self) {
93 if self.armed.load(Ordering::Relaxed) {
94 *self
95 .last_progress
96 .lock()
97 .unwrap_or_else(PoisonError::into_inner) = Instant::now();
98 }
99 }
100
101 fn last_progress(&self) -> Instant {
102 *self
103 .last_progress
104 .lock()
105 .unwrap_or_else(PoisonError::into_inner)
106 }
107}
108
109pub struct IdleWatch {
112 clock: Arc<ActivityClock>,
113 window: Duration,
114}
115
116impl IdleWatch {
117 pub(crate) async fn expired(&self) {
121 let mut timer = pin!(time::sleep_until(self.clock.last_progress() + self.window));
122 loop {
123 timer.as_mut().await;
124 let deadline = self.clock.last_progress() + self.window;
125 if deadline <= Instant::now() {
126 return;
127 }
128 timer.as_mut().reset(deadline);
129 }
130 }
131
132 pub(crate) fn refresh(&self) { self.clock.progressed(); }
135}
136
137impl Drop for IdleWatch {
138 fn drop(&mut self) { self.clock.armed.store(false, Ordering::Relaxed); }
139}