use crate::{driver::PendingGetClosestType, SwarmDriver};
use tokio::time::Duration;
use crate::target_arch::{interval, Instant, Interval};
pub(crate) const BOOTSTRAP_INTERVAL: Duration = Duration::from_secs(5);
const BOOTSTRAP_CONNECTED_PEERS_STEP: u32 = 5;
const LAST_PEER_ADDED_TIME_LIMIT: Duration = Duration::from_secs(180);
const LAST_BOOTSTRAP_TRIGGERED_TIME_LIMIT: Duration = Duration::from_secs(30);
const NO_PEER_ADDED_SLOWDOWN_INTERVAL: Duration = Duration::from_secs(300);
impl SwarmDriver {
pub(crate) async fn run_bootstrap_continuously(
&mut self,
current_bootstrap_interval: Duration,
) -> Option<Interval> {
let (should_bootstrap, new_interval) = self
.bootstrap
.should_we_bootstrap(self.connected_peers as u32, current_bootstrap_interval)
.await;
if should_bootstrap {
self.trigger_network_discovery();
}
if let Some(new_interval) = &new_interval {
debug!(
"The new bootstrap_interval has been updated to {:?}",
new_interval.period()
);
}
new_interval
}
pub(crate) fn trigger_network_discovery(&mut self) {
let now = Instant::now();
for addr in self.network_discovery.candidates() {
let query_id = self
.swarm
.behaviour_mut()
.kademlia
.get_closest_peers(addr.as_bytes());
let _ = self.pending_get_closest_peers.insert(
query_id,
(PendingGetClosestType::NetworkDiscovery, Default::default()),
);
}
self.bootstrap.initiated();
debug!("Trigger network discovery took {:?}", now.elapsed());
}
}
pub(crate) struct ContinuousBootstrap {
initial_bootstrap_done: bool,
last_peer_added_instant: Instant,
last_bootstrap_triggered: Option<Instant>,
}
impl ContinuousBootstrap {
pub(crate) fn new() -> Self {
Self {
initial_bootstrap_done: false,
last_peer_added_instant: Instant::now(),
last_bootstrap_triggered: None,
}
}
pub(crate) fn initiated(&mut self) {
self.last_bootstrap_triggered = Some(Instant::now());
}
pub(crate) fn notify_new_peer(&mut self) -> bool {
self.last_peer_added_instant = Instant::now();
if !self.initial_bootstrap_done {
self.initial_bootstrap_done = true;
true
} else {
false
}
}
pub(crate) async fn should_we_bootstrap(
&self,
peers_in_rt: u32,
current_interval: Duration,
) -> (bool, Option<Interval>) {
let is_ongoing = if let Some(last_bootstrap_triggered) = self.last_bootstrap_triggered {
last_bootstrap_triggered.elapsed() < LAST_BOOTSTRAP_TRIGGERED_TIME_LIMIT
} else {
false
};
let should_bootstrap = !is_ongoing && peers_in_rt >= 1;
if self.last_peer_added_instant.elapsed() > LAST_PEER_ADDED_TIME_LIMIT && peers_in_rt != 0 {
info!(
"It has been {LAST_PEER_ADDED_TIME_LIMIT:?} since we last added a peer to RT. Slowing down the continuous bootstrapping process"
);
let mut new_interval = interval(NO_PEER_ADDED_SLOWDOWN_INTERVAL);
new_interval.tick().await; return (should_bootstrap, Some(new_interval));
}
let step = peers_in_rt / BOOTSTRAP_CONNECTED_PEERS_STEP;
let step = std::cmp::max(1, step);
let new_interval = BOOTSTRAP_INTERVAL * step;
let new_interval = if new_interval > current_interval {
info!("More peers have been added to our RT!. Slowing down the continuous bootstrapping process");
let mut interval = interval(new_interval);
interval.tick().await; Some(interval)
} else {
None
};
(should_bootstrap, new_interval)
}
}