1use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::net::IpAddr;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub struct ProbeId(pub u32);
10
11impl fmt::Display for ProbeId {
12 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13 write!(f, "{}", self.0)
14 }
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19pub struct MeasurementId(pub u64);
20
21impl fmt::Display for MeasurementId {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 write!(f, "{}", self.0)
24 }
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
29pub struct Timestamp(pub i64);
30
31impl Timestamp {
32 pub fn now() -> Self {
33 Self(chrono::Utc::now().timestamp())
34 }
35}
36
37impl fmt::Display for Timestamp {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "{}", self.0)
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "lowercase")]
46pub enum MeasurementType {
47 Ping,
48 Traceroute,
49 Dns,
50 Http,
51 Tls,
52 Ntp,
53}
54
55impl fmt::Display for MeasurementType {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 match self {
58 MeasurementType::Ping => write!(f, "ping"),
59 MeasurementType::Traceroute => write!(f, "traceroute"),
60 MeasurementType::Dns => write!(f, "dns"),
61 MeasurementType::Http => write!(f, "http"),
62 MeasurementType::Tls => write!(f, "tls"),
63 MeasurementType::Ntp => write!(f, "ntp"),
64 }
65 }
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct MeasurementResult {
71 pub fw: u32,
73
74 #[serde(rename = "type")]
76 pub measurement_type: MeasurementType,
77
78 pub prb_id: ProbeId,
80
81 pub msm_id: MeasurementId,
83
84 pub timestamp: Timestamp,
86
87 pub af: u8,
89
90 pub dst_addr: IpAddr,
92
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub dst_name: Option<String>,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 pub src_addr: Option<IpAddr>,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub proto: Option<String>,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub ttl: Option<u8>,
108
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub size: Option<u16>,
112
113 pub data: MeasurementData,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
119#[serde(tag = "type", content = "data")]
120pub enum MeasurementData {
121 Generic(serde_json::Value),
123 PreFormatted(String),
126 FullLine(String),
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_probe_id_serde() {
138 let id = ProbeId(12345);
139 let json = serde_json::to_string(&id).unwrap();
140 assert_eq!(json, "12345");
141 let parsed: ProbeId = serde_json::from_str(&json).unwrap();
142 assert_eq!(id, parsed);
143 }
144
145 #[test]
146 fn test_measurement_type_serde() {
147 let mt = MeasurementType::Ping;
148 let json = serde_json::to_string(&mt).unwrap();
149 assert_eq!(json, "\"ping\"");
150 }
151}