use std::{collections::hash_map::DefaultHasher, hash::Hasher, net::IpAddr, time::Instant};
use super::FALLBACK_VERSION;
#[async_trait::async_trait]
pub trait ServerPeer: Send + Sync {
fn id(&self) -> u64 {
let mut hasher = DefaultHasher::new();
if let Some(p) = self.tcp_port() {
hasher.write_u16(p)
};
if let Some(p) = self.ssl_port() {
hasher.write_u16(p)
};
hasher.write(self.ip().to_string().as_bytes());
hasher.finish()
}
fn tcp_port(&self) -> Option<u16>;
fn ssl_port(&self) -> Option<u16>;
fn ip(&self) -> IpAddr;
fn hostname(&self) -> Option<String>;
fn pretty_hostname(&self) -> String;
fn version(&self) -> String;
fn last_candidate_request(&self) -> Option<Instant>;
}
impl std::fmt::Display for dyn ServerPeer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let safe_hostname = self
.hostname()
.unwrap_or(self.ip().to_string())
.chars()
.filter(|c| c.is_ascii())
.collect::<String>();
write!(
f,
"Peer {} - IP: {} TCP: {} SSL: {} version: {}",
safe_hostname,
self.ip(),
self.tcp_port().unwrap_or_default(),
self.ssl_port().unwrap_or_default(),
self.version()
)
}
}
#[derive(Debug, Clone)]
pub struct CandidatePeer {
pub(crate) tcp_port: Option<u16>,
pub(crate) ssl_port: Option<u16>,
#[allow(dead_code)]
pub(crate) ws_port: Option<u16>,
#[allow(dead_code)]
pub(crate) wss_port: Option<u16>,
pub(crate) hostname: Option<String>,
pub(crate) ip: IpAddr,
pub(crate) version: Option<String>,
}
impl ServerPeer for CandidatePeer {
fn tcp_port(&self) -> Option<u16> {
self.tcp_port
}
fn ssl_port(&self) -> Option<u16> {
self.ssl_port
}
fn ip(&self) -> IpAddr {
self.ip
}
fn hostname(&self) -> Option<String> {
self.hostname.clone()
}
fn version(&self) -> String {
match self.version.as_ref() {
Some(v) => v.clone(),
None => FALLBACK_VERSION.to_owned(),
}
}
fn pretty_hostname(&self) -> String {
if let Some(h) = self.hostname() {
format!("{} (IP: {})", h, self.ip())
} else {
self.ip().to_string()
}
}
fn last_candidate_request(&self) -> Option<Instant> {
None
}
}
#[derive(Debug, Clone)]
pub struct GoodKnownPeer {
pub tcp_port: Option<u16>,
pub ssl_port: Option<u16>,
pub hostname: Option<String>,
pub ip: IpAddr,
pub last_visit: Instant,
pub last_candidate_request: Option<Instant>,
pub version: String,
}
impl ServerPeer for GoodKnownPeer {
fn tcp_port(&self) -> Option<u16> {
self.tcp_port
}
fn ssl_port(&self) -> Option<u16> {
self.ssl_port
}
fn ip(&self) -> IpAddr {
self.ip
}
fn hostname(&self) -> Option<String> {
self.hostname.clone()
}
fn version(&self) -> String {
self.version.clone()
}
fn pretty_hostname(&self) -> String {
if let Some(h) = self.hostname() {
format!("{} (IP: {})", h, self.ip())
} else {
self.ip().to_string()
}
}
fn last_candidate_request(&self) -> Option<Instant> {
self.last_candidate_request
}
}