Skip to main content

netpulse/probers/
mod.rs

1// src/probers/mod.rs — Prober trait and shared types
2//
3// Each probe type (ICMP, TCP, UDP) implements this trait.
4// This is Rust's approach to polymorphism — no inheritance,
5// just traits — enabling a clean, extensible probe architecture.
6
7pub mod icmp;
8pub mod tcp;
9pub mod udp;
10
11use crate::error::NetPulseError;
12use async_trait::async_trait;
13use chrono::{DateTime, Utc};
14use serde::Serialize;
15
16/// A single probe measurement result.
17#[derive(Debug, Clone, Serialize)]
18pub struct ProbeResult {
19    /// Target host or IP that was probed.
20    pub target: String,
21    /// Round-trip time in microseconds. None means packet loss.
22    pub rtt_us: Option<u64>,
23    /// UTC timestamp of when the probe was sent.
24    pub timestamp: DateTime<Utc>,
25    /// Sequence number of this probe (for reorder detection).
26    pub seq: u64,
27    /// The IP address that responded. Useful for traceroute (ICMP Time Exceeded).
28    pub responder_ip: Option<String>,
29}
30
31impl ProbeResult {
32    pub fn loss(target: &str, seq: u64) -> Self {
33        Self {
34            target: target.to_string(),
35            rtt_us: None,
36            timestamp: Utc::now(),
37            seq,
38            responder_ip: None,
39        }
40    }
41
42    pub fn success(target: &str, seq: u64, rtt_us: u64, responder_ip: Option<String>) -> Self {
43        Self {
44            target: target.to_string(),
45            rtt_us: Some(rtt_us),
46            timestamp: Utc::now(),
47            seq,
48            responder_ip,
49        }
50    }
51
52    /// Returns true if the probe resulted in packet loss.
53    pub fn is_loss(&self) -> bool {
54        self.rtt_us.is_none()
55    }
56}
57
58/// The core abstraction for all probe types.
59///
60/// Every prober must be Send + Sync so it can be shared across
61/// async Tokio tasks without data races.
62#[async_trait]
63pub trait Prober: Send + Sync {
64    /// Fire a single probe toward `target` and return the result.
65    async fn probe(
66        &self,
67        target: &str,
68        seq: u64,
69        ttl: Option<u32>,
70    ) -> Result<ProbeResult, NetPulseError>;
71
72    /// Human-readable name of this probe type, e.g. "icmp" or "tcp".
73    fn name(&self) -> &'static str;
74}