1use std::{
2 collections::VecDeque,
3 convert::Infallible,
4 io, mem,
5 task::{Context, Poll, Waker},
6 time::Duration,
7};
8
9use futures::{
10 FutureExt,
11 future::{self, BoxFuture},
12};
13use futures_timer::Delay;
14use volans_core::{PeerId, Multiaddr, upgrade::ReadyUpgrade};
15use volans_swarm::{
16 BehaviorEvent, ConnectionDenied, ConnectionHandler, ConnectionHandlerEvent, ConnectionId,
17 NetworkBehavior, NetworkOutgoingBehavior, OutboundStreamHandler, OutboundUpgradeSend,
18 StreamProtocol, StreamUpgradeError, Substream, SubstreamProtocol, THandlerAction,
19 THandlerEvent,
20};
21
22use crate::{Config, Event, Failure, protocol};
23
24pub struct Handler {
25 interval: Delay,
26 config: Config,
27 failures: u32,
28 outbound: OutboundState,
29 pending_errors: VecDeque<Failure>,
30 state: State,
31}
32
33impl Handler {
34 pub fn new(config: Config) -> Self {
35 Self {
36 interval: Delay::new(config.interval),
37 config,
38 failures: 0,
39 outbound: OutboundState::None,
40 pending_errors: VecDeque::new(),
41 state: State::Active,
42 }
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47enum State {
48 Inactive { reported: bool },
49 Active,
50}
51
52enum OutboundState {
53 None,
54 OpenStream,
55 Idle(Substream),
56 Ping(PingFuture),
57}
58
59type PingFuture = BoxFuture<'static, Result<(Substream, Duration), Failure>>;
60
61impl ConnectionHandler for Handler {
62 type Action = Infallible;
63 type Event = Result<Duration, Failure>;
64
65 fn handle_action(&mut self, _action: Self::Action) {
66 unreachable!("Ping handler does not support actions");
67 }
68
69 fn poll_close(&mut self, _: &mut Context<'_>) -> Poll<Option<Self::Event>> {
70 if let Some(error) = self.pending_errors.pop_back() {
71 return Poll::Ready(Some(Err(error)));
72 }
73 Poll::Ready(None)
74 }
75
76 fn poll(&mut self, cx: &mut Context<'_>) -> Poll<ConnectionHandlerEvent<Self::Event>> {
77 match self.state {
78 State::Inactive { reported: true } => {
79 return Poll::Pending;
80 }
81 State::Inactive { reported: false } => {
82 self.state = State::Inactive { reported: true };
83 return Poll::Ready(ConnectionHandlerEvent::Notify(Err(Failure::Unsupported)));
84 }
85 State::Active => {}
86 }
87
88 loop {
89 if let Some(error) = self.pending_errors.pop_back() {
90 self.failures += 1;
91 return Poll::Ready(ConnectionHandlerEvent::Notify(Err(error)));
92 }
93
94 if self.failures >= self.config.failures {
96 return Poll::Ready(ConnectionHandlerEvent::CloseConnection);
97 }
98
99 match mem::replace(&mut self.outbound, OutboundState::None) {
100 OutboundState::None => {}
101 OutboundState::OpenStream => {
102 self.outbound = OutboundState::OpenStream;
103 }
104 OutboundState::Idle(stream) => match self.interval.poll_unpin(cx) {
105 Poll::Pending => {
106 self.outbound = OutboundState::Idle(stream);
107 }
108 Poll::Ready(()) => {
109 self.outbound =
111 OutboundState::Ping(send_ping(stream, self.config.timeout).boxed());
112 continue;
113 }
114 },
115 OutboundState::Ping(mut ping) => match ping.poll_unpin(cx) {
116 Poll::Pending => {
117 self.outbound = OutboundState::Ping(ping);
118 return Poll::Pending;
119 }
120 Poll::Ready(Ok((stream, rtt))) => {
121 self.failures = 0;
123 self.interval.reset(self.config.interval);
124 self.outbound = OutboundState::Idle(stream);
125 return Poll::Ready(ConnectionHandlerEvent::Notify(Ok(rtt)));
126 }
127 Poll::Ready(Err(e)) => {
128 self.interval.reset(self.config.interval);
130 self.pending_errors.push_front(e);
131 continue;
132 }
133 },
134 }
135 return Poll::Pending;
136 }
137 }
138}
139
140impl OutboundStreamHandler for Handler {
141 type OutboundUpgrade = ReadyUpgrade<StreamProtocol>;
142 type OutboundUserData = ();
143
144 fn on_fully_negotiated(
145 &mut self,
146 _user_data: Self::OutboundUserData,
147 stream: <Self::OutboundUpgrade as OutboundUpgradeSend>::Output,
148 ) {
149 self.outbound = OutboundState::Ping(send_ping(stream, self.config.timeout).boxed());
150 }
151
152 fn on_upgrade_error(
153 &mut self,
154 _user_data: Self::OutboundUserData,
155 error: StreamUpgradeError<<Self::OutboundUpgrade as OutboundUpgradeSend>::Error>,
156 ) {
157 self.outbound = OutboundState::None;
158 self.interval.reset(Duration::new(0, 0));
159 let error = match error {
160 StreamUpgradeError::Timeout => Failure::other(io::Error::new(
161 io::ErrorKind::TimedOut,
162 "Ping protocol negotiation timed out",
163 )),
164 StreamUpgradeError::NegotiationFailed => {
165 debug_assert_eq!(self.state, State::Active);
166 self.state = State::Inactive { reported: false };
167 return;
168 }
169 StreamUpgradeError::Apply(err) => Failure::other(err),
170 StreamUpgradeError::Io(err) => Failure::other(err),
171 };
172
173 self.pending_errors.push_back(error);
174 }
175
176 fn poll_outbound_request(
177 &mut self,
178 cx: &mut Context<'_>,
179 ) -> Poll<SubstreamProtocol<Self::OutboundUpgrade, Self::OutboundUserData>> {
180 match self.outbound {
181 OutboundState::None => match self.interval.poll_unpin(cx) {
182 Poll::Pending => {}
183 Poll::Ready(()) => {
184 self.outbound = OutboundState::OpenStream;
186 let protocol =
187 SubstreamProtocol::new(ReadyUpgrade::new(protocol::PROTOCOL_NAME), ());
188 return Poll::Ready(protocol);
189 }
190 },
191 _ => {}
192 }
193 Poll::Pending
194 }
195}
196
197pub struct Behavior {
198 config: Config,
199 events: VecDeque<Event>,
200 none_event_waker: Option<Waker>,
201}
202
203impl Behavior {
204 pub fn new(config: Config) -> Self {
205 Self {
206 config,
207 events: VecDeque::new(),
208 none_event_waker: None,
209 }
210 }
211}
212
213impl Default for Behavior {
214 fn default() -> Self {
215 Self::new(Config::default())
216 }
217}
218
219impl NetworkBehavior for Behavior {
220 type ConnectionHandler = Handler;
221 type Event = Event;
222
223 fn on_connection_handler_event(
224 &mut self,
225 id: ConnectionId,
226 peer_id: PeerId,
227 event: THandlerEvent<Self>,
228 ) {
229 self.events.push_front(Event {
230 peer_id,
231 connection: id,
232 result: event,
233 });
234 if let Some(waker) = self.none_event_waker.take() {
235 waker.wake();
236 }
237 }
238
239 fn poll(
240 &mut self,
241 _cx: &mut Context<'_>,
242 ) -> Poll<BehaviorEvent<Self::Event, THandlerAction<Self>>> {
243 if let Some(event) = self.events.pop_back() {
244 return Poll::Ready(BehaviorEvent::Behavior(event));
245 }
246 self.none_event_waker = Some(_cx.waker().clone());
247 Poll::Pending
248 }
249}
250
251impl NetworkOutgoingBehavior for Behavior {
252 fn handle_established_connection(
253 &mut self,
254 id: ConnectionId,
255 peer_id: PeerId,
256 addr: &Multiaddr,
257 ) -> Result<Self::ConnectionHandler, ConnectionDenied> {
258 tracing::trace!(
259 "Ping handler established for peer: {}, {}, {}",
260 id,
261 peer_id,
262 addr
263 );
264 Ok(Handler::new(self.config.clone()))
265 }
266}
267
268async fn send_ping(stream: Substream, timeout: Duration) -> Result<(Substream, Duration), Failure> {
269 let ping = protocol::send_ping(stream);
270 futures::pin_mut!(ping);
271
272 match future::select(ping, Delay::new(timeout)).await {
273 future::Either::Left((Ok((stream, rtt)), _)) => Ok((stream, rtt)),
274 future::Either::Left((Err(e), _)) => Err(Failure::other(e)),
275 future::Either::Right(((), _)) => Err(Failure::Timeout),
276 }
277}