This behaviour makes Bob re-dial Alice with an exponential backoff as soon as the connection is lost.pull/407/head
parent
d4c10a1292
commit
f0f7288bb6
@ -0,0 +1,119 @@
|
||||
use backoff::backoff::Backoff;
|
||||
use backoff::ExponentialBackoff;
|
||||
use futures::future::FutureExt;
|
||||
use libp2p::core::connection::ConnectionId;
|
||||
use libp2p::core::Multiaddr;
|
||||
use libp2p::swarm::protocols_handler::DummyProtocolsHandler;
|
||||
use libp2p::swarm::{DialPeerCondition, NetworkBehaviour, NetworkBehaviourAction, PollParameters};
|
||||
use libp2p::PeerId;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::Duration;
|
||||
use tokio::time::{Instant, Sleep};
|
||||
use void::Void;
|
||||
|
||||
pub enum OutEvent {
|
||||
AllAttemptsExhausted { peer: PeerId },
|
||||
}
|
||||
|
||||
/// A [`NetworkBehaviour`] that tracks whether we are connected to the given
|
||||
/// peer and attempts to re-establish a connection with an exponential backoff
|
||||
/// if we lose the connection.
|
||||
pub struct Behaviour {
|
||||
/// The peer we are interested in.
|
||||
peer: PeerId,
|
||||
/// If present, tracks for how long we need to sleep until we dial again.
|
||||
sleep: Option<Pin<Box<Sleep>>>,
|
||||
/// Tracks the current backoff state.
|
||||
backoff: ExponentialBackoff,
|
||||
}
|
||||
|
||||
impl Behaviour {
|
||||
pub fn new(peer: PeerId, interval: Duration) -> Self {
|
||||
Self {
|
||||
peer,
|
||||
sleep: None,
|
||||
backoff: ExponentialBackoff {
|
||||
initial_interval: interval,
|
||||
current_interval: interval,
|
||||
// give up dialling after 5 minutes
|
||||
max_elapsed_time: Some(Duration::from_secs(5 * 60)),
|
||||
..ExponentialBackoff::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn until_next_redial(&self) -> Option<Duration> {
|
||||
let until_next_redial = self
|
||||
.sleep
|
||||
.as_ref()?
|
||||
.deadline()
|
||||
.checked_duration_since(Instant::now())?;
|
||||
|
||||
Some(until_next_redial)
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkBehaviour for Behaviour {
|
||||
type ProtocolsHandler = DummyProtocolsHandler;
|
||||
type OutEvent = OutEvent;
|
||||
|
||||
fn new_handler(&mut self) -> Self::ProtocolsHandler {
|
||||
DummyProtocolsHandler::default()
|
||||
}
|
||||
|
||||
fn addresses_of_peer(&mut self, _: &PeerId) -> Vec<Multiaddr> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn inject_connected(&mut self, peer_id: &PeerId) {
|
||||
if peer_id != &self.peer {
|
||||
return;
|
||||
}
|
||||
|
||||
// established a connection to the desired peer, cancel any active re-dialling
|
||||
self.sleep = None;
|
||||
}
|
||||
|
||||
fn inject_disconnected(&mut self, peer_id: &PeerId) {
|
||||
if peer_id != &self.peer {
|
||||
return;
|
||||
}
|
||||
|
||||
// lost connection to the configured peer, trigger re-dialling with an
|
||||
// exponential backoff
|
||||
self.backoff.reset();
|
||||
self.sleep = Some(Box::pin(tokio::time::sleep(self.backoff.initial_interval)));
|
||||
}
|
||||
|
||||
fn inject_event(&mut self, _: PeerId, _: ConnectionId, _: Void) {}
|
||||
|
||||
fn poll(
|
||||
&mut self,
|
||||
cx: &mut Context<'_>,
|
||||
_: &mut impl PollParameters,
|
||||
) -> Poll<NetworkBehaviourAction<Void, Self::OutEvent>> {
|
||||
let sleep = match self.sleep.as_mut() {
|
||||
None => return Poll::Pending, // early exit if we shouldn't be re-dialling
|
||||
Some(future) => future,
|
||||
};
|
||||
|
||||
futures::ready!(sleep.poll_unpin(cx));
|
||||
|
||||
let next_dial_in = match self.backoff.next_backoff() {
|
||||
Some(next_dial_in) => next_dial_in,
|
||||
None => {
|
||||
return Poll::Ready(NetworkBehaviourAction::GenerateEvent(
|
||||
OutEvent::AllAttemptsExhausted { peer: self.peer },
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
self.sleep = Some(Box::pin(tokio::time::sleep(next_dial_in)));
|
||||
|
||||
Poll::Ready(NetworkBehaviourAction::DialPeer {
|
||||
peer_id: self.peer,
|
||||
condition: DialPeerCondition::Disconnected,
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in new issue