use std::collections::VecDeque;
use datasize::DataSize;
use rand::{seq::SliceRandom, Rng};
#[derive(DataSize, Debug)]
pub struct PeersState<I> {
peers: Vec<I>,
peers_to_try: Vec<I>,
succ_peers: VecDeque<I>,
succ_attempts: u8,
succ_attempts_max: u8,
}
impl<I: Clone + PartialEq + 'static> PeersState<I> {
pub fn new() -> Self {
PeersState {
peers: Default::default(),
peers_to_try: Default::default(),
succ_peers: Default::default(),
succ_attempts: 0,
succ_attempts_max: 5,
}
}
pub(crate) fn reset<R: Rng + ?Sized>(&mut self, rng: &mut R) {
self.peers_to_try = self.peers.clone();
self.peers_to_try.as_mut_slice().shuffle(rng);
}
pub(crate) fn random(&mut self) -> Option<I> {
if self.succ_attempts < self.succ_attempts_max {
self.next_succ().or_else(|| self.peers_to_try.pop())
} else {
self.succ_attempts = 0;
self.peers_to_try.pop().or_else(|| self.next_succ())
}
}
pub(crate) fn random_unsafe(&mut self) -> I {
self.random().expect("At least one peer available.")
}
pub(crate) fn ban(&mut self, peer: &I) {
self.peers.retain(|p| p != peer);
self.succ_peers.retain(|p| p != peer);
}
pub(crate) fn is_empty(&self) -> bool {
self.peers.is_empty()
}
pub(crate) fn push(&mut self, peer: I) {
self.peers.push(peer.clone());
self.peers_to_try.push(peer);
}
fn next_succ(&mut self) -> Option<I> {
let peer = self.succ_peers.pop_front()?;
self.succ_peers.push_back(peer.clone());
Some(peer)
}
pub(crate) fn failure(&mut self, peer: &I) {
self.succ_peers.retain(|id| id != peer);
}
pub(crate) fn success(&mut self, peer: I) {
self.succ_attempts += 1;
self.succ_peers.push_back(peer);
}
}