From f51ff19f0484510b418e0d0c8f148925e129cabd Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Wed, 30 Sep 2026 15:34:54 +0700 Subject: [PATCH] feat(measurement): add core data models --- src/main.rs | 1 + src/measurement/mod.rs | 2 + src/measurement/model.rs | 96 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/measurement/mod.rs create mode 100644 src/measurement/model.rs diff --git a/src/main.rs b/src/main.rs index ad6c000..a6f92a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate core; mod baseliner; mod log; +mod measurement; mod metrics; mod pinger; mod pinger_icmp; diff --git a/src/measurement/mod.rs b/src/measurement/mod.rs new file mode 100644 index 0000000..e152830 --- /dev/null +++ b/src/measurement/mod.rs @@ -0,0 +1,2 @@ +mod icmp; +mod model; diff --git a/src/measurement/model.rs b/src/measurement/model.rs new file mode 100644 index 0000000..2d8d959 --- /dev/null +++ b/src/measurement/model.rs @@ -0,0 +1,96 @@ +use std::{ + net::IpAddr, + time::{Duration, Instant}, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MeasurementStreamId(pub u64); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum MeasurementSource { + IcmpEcho, + IcmpTimestamp, + Irtt, + TcpSeqAck, + TcpTimestamp, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct MeasurementStream { + pub id: MeasurementStreamId, + pub peer: IpAddr, + pub source: MeasurementSource, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum OneWayClock { + Uncalibrated, + Calibrated, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct SignedDuration { + nanos: i64, +} + +impl SignedDuration { + pub const fn from_nanos(nanos: i64) -> Self { + Self { nanos } + } + + pub const fn from_millis(millis: i64) -> Self { + Self { + nanos: millis * 1_000_000, + } + } + + pub const fn as_nanos(self) -> i64 { + self.nanos + } + + pub fn as_secs_f64(self) -> f64 { + self.nanos as f64 / 1_000_000_000.0 + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct OneWayLatency { + pub uplink: SignedDuration, + pub downlink: SignedDuration, + pub clock: OneWayClock, +} + +#[derive(Debug, Clone, Copy)] +pub struct MeasurementObservation { + pub stream: MeasurementStream, + + /// Local monotonic time at which measurement started. + pub started_at: Instant, + + /// Local monotonic time at which the result was observed. + pub observed_at: Instant, + + /// Directional timing, when the measurement mechanism can provide it. + pub one_way: Option, +} + +impl MeasurementObservation { + pub fn rtt(&self) -> Duration { + self.observed_at.duration_since(self.started_at) + } + + pub fn rtt_ms(&self) -> f64 { + self.rtt().as_secs_f64() * 1000.0 + } +} + +pub struct MeasurementLoss { + pub stream: MeasurementStream, + pub started_at: Instant, + pub detected_at: Instant, +} + +pub enum MeasurementEvent { + Observation(MeasurementObservation), + Loss(MeasurementLoss), +}