use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::hash::Hasher;
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime};
use network_primitives::address::{
net_address::NetAddress,
peer_address::PeerAddress
};
use crate::connection::close_type::CloseType;
use crate::peer_channel::PeerChannel;
use network_primitives::protocol::Protocol;
pub struct PeerAddressInfo {
pub peer_address: Arc<PeerAddress>,
pub state: PeerAddressState,
pub signal_router: SignalRouter,
pub last_connected: Option<SystemTime>,
pub failed_attempts: u32,
pub banned_until: Option<Instant>,
pub ban_backoff: Duration,
pub close_types: HashMap<CloseType, usize>,
pub added_by: HashSet<Arc<NetAddress>>,
}
impl PeerAddressInfo {
pub fn new(peer_address: Arc<PeerAddress>) -> Self {
PeerAddressInfo {
peer_address: Arc::clone(&peer_address),
state: PeerAddressState::New,
signal_router: SignalRouter::new(peer_address),
last_connected: None,
failed_attempts: 0,
banned_until: None,
ban_backoff: super::peer_address_book::INITIAL_FAILED_BACKOFF,
close_types: HashMap::new(),
added_by: HashSet::new(),
}
}
pub fn max_failed_attempts(&self) -> u32 {
match self.peer_address.protocol() {
Protocol::Rtc => super::peer_address_book::MAX_FAILED_ATTEMPTS_RTC,
Protocol::Ws | Protocol::Wss => super::peer_address_book::MAX_FAILED_ATTEMPTS_WS,
_ => 0
}
}
pub fn close(&mut self, ty: CloseType) {
*self.close_types.entry(ty)
.or_insert(0) += 1;
if self.state == PeerAddressState::Banned {
return;
}
if ty.is_banning_type() {
self.state = PeerAddressState::Banned;
} else if ty.is_failing_type() {
self.state = PeerAddressState::Failed;
} else {
self.state = PeerAddressState::Tried;
}
}
}
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum PeerAddressState {
New = 1,
Established = 2,
Tried = 3,
Failed = 4,
Banned = 5
}
pub struct SignalRouter {
peer_address: Arc<PeerAddress>,
pub best_route: Option<SignalRouteInfo>,
routes: HashSet<SignalRouteInfo>
}
impl SignalRouter {
pub fn new(peer_address: Arc<PeerAddress>) -> Self {
SignalRouter {
peer_address,
best_route: None,
routes: HashSet::new()
}
}
pub fn add_route(&mut self, signal_channel: Arc<PeerChannel>, distance: u8, timestamp: u64) -> bool {
let mut new_route = SignalRouteInfo::new(signal_channel, distance, timestamp);
let old_route = self.routes.get(&new_route);
if let Some(old_route) = old_route {
new_route.failed_attempts = old_route.failed_attempts;
}
self.routes.replace(new_route.clone());
let is_new_best = match &self.best_route {
Some(route) => new_route.score() > route.score()
|| (new_route.score() == route.score() && timestamp > route.timestamp),
None => true
};
if is_new_best {
if let Some(ref mut peer_addr_mut) = Arc::get_mut(&mut self.peer_address) {
peer_addr_mut.distance = new_route.distance;
}
self.best_route = Some(new_route);
return true;
}
false
}
pub fn delete_best_route(&mut self) {
if let Some(best_route) = &self.best_route {
let signal_channel = best_route.signal_channel.clone();
self.delete_route(signal_channel);
}
}
pub fn delete_route(&mut self, signal_channel: Arc<PeerChannel>) {
let route = SignalRouteInfo::new(signal_channel, 0, 0); self.routes.remove(&route);
if let Some(best_route) = &self.best_route {
if *best_route == route {
self.update_best_route();
}
}
}
pub fn delete_all_routes(&mut self) {
self.best_route = None;
self.routes.clear();
}
pub fn has_route(&self) -> bool {
!self.routes.is_empty()
}
pub fn update_best_route(&mut self) {
let mut best_route: Option<SignalRouteInfo> = None;
for route in self.routes.iter() {
match best_route {
Some(ref mut best_route) => {
if route.score() > best_route.score() ||
(route.score() == best_route.score() && route.timestamp > best_route.timestamp) {
*best_route = route.clone()
}
},
None => best_route = Some(route.clone()),
}
}
self.best_route = best_route;
let mut distance = super::peer_address_book::MAX_DISTANCE + 1;
if let Some(ref best_route) = self.best_route {
distance = best_route.distance;
}
if let Some(peer_address) = Arc::get_mut(&mut self.peer_address) {
peer_address.distance = distance;
}
}
}
#[derive(Clone)]
pub struct SignalRouteInfo {
failed_attempts: u32,
pub timestamp: u64,
pub signal_channel: Arc<PeerChannel>,
distance: u8
}
impl SignalRouteInfo {
pub fn new(signal_channel: Arc<PeerChannel>, distance: u8, timestamp: u64) -> Self {
let signal_channel = signal_channel.clone();
SignalRouteInfo {
failed_attempts: 0,
timestamp,
signal_channel,
distance
}
}
pub fn score(&self) -> u32 {
u32::from((super::peer_address_book::MAX_DISTANCE - self.distance) / 2) * (1 - self.failed_attempts / super::peer_address_book::MAX_FAILED_ATTEMPTS_RTC)
}
}
impl PartialEq for SignalRouteInfo {
fn eq(&self, other: &SignalRouteInfo) -> bool {
self.signal_channel == other.signal_channel
}
}
impl Eq for SignalRouteInfo {}
impl Hash for SignalRouteInfo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.signal_channel.hash(state);
}
}