use std::collections::HashSet;
use std::net::SocketAddr;
pub(crate) struct UploadManager {
max_uploads: u32,
unchoked: HashSet<SocketAddr>,
}
impl UploadManager {
pub fn new(max_uploads: u32) -> Self {
UploadManager {
max_uploads,
unchoked: HashSet::new(),
}
}
pub fn is_unchoked(&self, addr: &SocketAddr) -> bool {
self.unchoked.contains(addr)
}
pub fn choke(&mut self, addr: &SocketAddr) {
tracing::debug!("choke peer {}", addr);
self.unchoked.remove(addr);
}
pub fn unchoke(&mut self, addr: SocketAddr) {
tracing::debug!("unchoke peer {}", addr);
if self.unchoked.len() < self.max_uploads as usize {
self.unchoked.insert(addr);
}
}
#[allow(dead_code)]
pub fn num_unchoked(&self) -> usize {
self.unchoked.len()
}
pub fn unchoked_peers(&self) -> impl Iterator<Item = &SocketAddr> {
self.unchoked.iter()
}
pub fn max_uploads(&self) -> u32 {
self.max_uploads
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::{IpAddr, Ipv4Addr};
fn test_addr(n: u8) -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, n)), 6881)
}
#[test]
fn new_has_no_unchoked() {
let um = UploadManager::new(5);
assert_eq!(um.num_unchoked(), 0);
}
#[test]
fn unchoke_peer() {
let mut um = UploadManager::new(5);
let addr = test_addr(1);
assert!(!um.is_unchoked(&addr));
um.unchoke(addr);
assert!(um.is_unchoked(&addr));
}
#[test]
fn choke_peer() {
let mut um = UploadManager::new(5);
let addr = test_addr(1);
um.unchoke(addr);
assert!(um.is_unchoked(&addr));
um.choke(&addr);
assert!(!um.is_unchoked(&addr));
}
#[test]
fn unchoke_respects_max_uploads() {
let mut um = UploadManager::new(2);
let a1 = test_addr(1);
let a2 = test_addr(2);
let a3 = test_addr(3);
um.unchoke(a1);
um.unchoke(a2);
um.unchoke(a3); assert_eq!(um.num_unchoked(), 2);
assert!(um.is_unchoked(&a1));
assert!(um.is_unchoked(&a2));
assert!(!um.is_unchoked(&a3));
}
#[test]
fn unchoked_peers_iterator() {
let mut um = UploadManager::new(5);
let a1 = test_addr(1);
let a2 = test_addr(2);
um.unchoke(a1);
um.unchoke(a2);
let peers: Vec<&SocketAddr> = um.unchoked_peers().collect();
assert_eq!(peers.len(), 2);
assert!(peers.contains(&&a1));
assert!(peers.contains(&&a2));
}
#[test]
fn max_uploads_accessor() {
let um = UploadManager::new(8);
assert_eq!(um.max_uploads(), 8);
}
#[test]
fn choke_nonexistent_peer() {
let mut um = UploadManager::new(5);
let addr = test_addr(99);
um.choke(&addr); assert_eq!(um.num_unchoked(), 0);
}
}