Skip to main content

volans_ping/
outbound.rs

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            // 如果失败次数超过配置的最大值,关闭连接
95            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                        // 间隔到达, State: Idle -> Ping
110                        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                        // Ping 成功,重置失败计数器 State: Ping -> Idle
122                        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                        // Ping 超时或失败 State: Ping -> None
129                        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                    // 首次间隔到达, State: None -> OpenStream
185                    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}