use crate::server::connection::ConnectionId;
use crate::utils::clock::Instant;
use std::collections::HashMap;
use std::net::SocketAddr;
use std::time::Duration;
use tokio::sync::RwLock;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PeerAdmission {
Deciding,
Accepted,
Rejected,
}
#[derive(Clone)]
pub struct Peer {
pub connection_id: ConnectionId,
pub addr: SocketAddr,
pub session_id: u64,
pub key_id: u8,
pub admission: PeerAdmission,
pub saw_control_payload: bool,
pub saw_data_packet: bool,
pub bytes_sent: u64,
pub bytes_received: u64,
pub last_activity: Instant,
}
impl Peer {
pub fn new(connection_id: ConnectionId, addr: SocketAddr, session_id: u64, key_id: u8) -> Self {
Peer {
connection_id,
addr,
session_id,
key_id,
admission: PeerAdmission::Deciding,
saw_control_payload: false,
saw_data_packet: false,
bytes_sent: 0,
bytes_received: 0,
last_activity: Instant::now(),
}
}
pub fn record_sent(&mut self, bytes: u64) {
self.bytes_sent = self.bytes_sent.saturating_add(bytes);
self.last_activity = Instant::now();
}
pub fn record_received(&mut self, bytes: u64) {
self.bytes_received = self.bytes_received.saturating_add(bytes);
self.last_activity = Instant::now();
}
}
pub struct PeerManager {
peers: RwLock<HashMap<SocketAddr, Peer>>,
}
impl PeerManager {
pub fn new() -> Self {
PeerManager {
peers: RwLock::new(HashMap::new()),
}
}
pub async fn add_peer(&self, peer: Peer) {
self.peers.write().await.insert(peer.addr, peer);
}
pub async fn get_peer(&self, addr: &SocketAddr) -> Option<Peer> {
self.peers.read().await.get(addr).cloned()
}
pub async fn update_peer<F>(&self, addr: &SocketAddr, f: F)
where
F: FnOnce(&mut Peer),
{
if let Some(peer) = self.peers.write().await.get_mut(addr) {
f(peer);
}
}
pub async fn update_peer_returning<F, T>(&self, addr: &SocketAddr, f: F) -> Option<T>
where
F: FnOnce(&mut Peer) -> T,
{
self.peers.write().await.get_mut(addr).map(f)
}
pub async fn set_admission(&self, addr: &SocketAddr, admission: PeerAdmission) {
self.update_peer(addr, |p| {
p.admission = admission;
p.last_activity = Instant::now();
})
.await;
}
pub async fn touch(&self, addr: &SocketAddr) {
self.update_peer(addr, |p| p.last_activity = Instant::now())
.await;
}
pub async fn remove_peer(&self, addr: &SocketAddr) -> Option<Peer> {
self.peers.write().await.remove(addr)
}
pub async fn remove_idle_peers(&self, max_idle: Duration) -> Vec<Peer> {
let now = Instant::now();
let mut peers = self.peers.write().await;
let expired: Vec<SocketAddr> = peers
.iter()
.filter(|(_, p)| now.duration_since(p.last_activity) > max_idle)
.map(|(addr, _)| *addr)
.collect();
expired
.into_iter()
.filter_map(|addr| peers.remove(&addr))
.collect()
}
pub async fn get_all_peers(&self) -> Vec<Peer> {
self.peers.read().await.values().cloned().collect()
}
pub async fn count(&self) -> usize {
self.peers.read().await.len()
}
}
impl Default for PeerManager {
fn default() -> Self {
Self::new()
}
}