use crate::traceroute::{AsnInfo, SegmentType};
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct RawHopInfo {
pub ttl: u8,
pub addr: Option<IpAddr>,
pub rtt: Option<Duration>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClassifiedHopInfo {
pub ttl: u8,
pub segment: SegmentType,
pub hostname: Option<String>,
pub addr: Option<IpAddr>,
pub asn_info: Option<AsnInfo>,
pub rtt: Option<Duration>,
}
impl ClassifiedHopInfo {
pub fn is_destination(&self, target: IpAddr) -> bool {
self.addr == Some(target)
}
pub fn rtt_ms(&self) -> Option<f64> {
self.rtt.map(|d| d.as_secs_f64() * 1000.0)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IspInfo {
pub public_ip: IpAddr,
pub asn: u32,
pub name: String,
pub hostname: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::Ipv4Addr;
#[test]
fn test_raw_hop_info() {
let hop = RawHopInfo {
ttl: 5,
addr: Some(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
rtt: Some(Duration::from_millis(10)),
};
assert_eq!(hop.ttl, 5);
assert!(hop.addr.is_some());
assert_eq!(hop.rtt.unwrap().as_millis(), 10);
}
#[test]
fn test_classified_hop_info() {
let hop = ClassifiedHopInfo {
ttl: 10,
segment: SegmentType::Isp,
hostname: Some("router.example.com".to_string()),
addr: Some(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))),
asn_info: None,
rtt: Some(Duration::from_millis(25)),
};
assert_eq!(hop.ttl, 10);
assert_eq!(hop.segment, SegmentType::Isp);
assert_eq!(hop.rtt_ms(), Some(25.0));
assert!(!hop.is_destination(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1))));
assert!(hop.is_destination(IpAddr::V4(Ipv4Addr::new(8, 8, 8, 8))));
}
#[test]
fn test_isp_info() {
let isp = IspInfo {
public_ip: IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4)),
asn: 12345,
name: "Example ISP".to_string(),
hostname: Some("customer.example-isp.com".to_string()),
};
assert_eq!(isp.asn, 12345);
assert_eq!(isp.name, "Example ISP");
}
}