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}