1use std::fmt;
9use std::sync::atomic::{AtomicU64, Ordering};
10use std::sync::{Arc, Mutex};
11
12use crate::wire_tap::WireTap;
13
14#[derive(Debug, Default, Clone)]
21pub struct TrafficStats {
22 requests: Arc<AtomicU64>,
23 responses: Arc<AtomicU64>,
24 errors: Arc<AtomicU64>,
25}
26
27impl TrafficStats {
28 pub fn new() -> Self {
30 Self::default()
31 }
32 pub fn count_requests(&self) -> u64 {
34 self.requests.load(Ordering::Relaxed)
35 }
36 pub fn count_responses(&self) -> u64 {
38 self.responses.load(Ordering::Relaxed)
39 }
40 pub fn count_errors(&self) -> u64 {
42 self.errors.load(Ordering::Relaxed)
43 }
44 pub fn reset(&self) {
50 self.requests.store(0, Ordering::Relaxed);
51 self.responses.store(0, Ordering::Relaxed);
52 self.errors.store(0, Ordering::Relaxed);
53 }
54}
55
56impl WireTap for TrafficStats {
57 fn on_write(&self, _bytes: &[u8], _ts: u64) {
58 self.requests.fetch_add(1, Ordering::Relaxed);
59 }
60 fn on_read(&self, _bytes: &[u8], _ts: u64) {
61 self.responses.fetch_add(1, Ordering::Relaxed);
62 }
63 fn on_error(&self, _bytes: &[u8], _error: &str, _ts: u64) {
64 self.errors.fetch_add(1, Ordering::Relaxed);
65 }
66}
67
68#[derive(Debug, Clone)]
72#[non_exhaustive]
73pub enum PacketData {
74 RawTx(Vec<u8>),
76 RawRx(Vec<u8>),
78 RawError(Vec<u8>, String),
80}
81
82#[derive(Debug, Clone)]
84pub struct PacketRecord {
85 pub timestamp_us: u64,
86 pub data: PacketData,
87}
88
89impl fmt::Display for PacketRecord {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 let ts = format_timestamp(self.timestamp_us);
92 match &self.data {
93 PacketData::RawTx(bytes) => {
94 write!(f, "[TX] {ts} {:>3}B ", bytes.len())?;
95 write_hex(f, bytes)
96 }
97 PacketData::RawRx(bytes) => {
98 write!(f, "[RX] {ts} {:>3}B ", bytes.len())?;
99 write_hex(f, bytes)
100 }
101 PacketData::RawError(bytes, err) => {
102 write!(f, "[ERR] {ts} {:>3}B ", bytes.len())?;
103 write_hex(f, bytes)?;
104 write!(f, " — {err}")
105 }
106 }
107 }
108}
109
110pub fn format_timestamp(timestamp_us: u64) -> String {
131 let secs = (timestamp_us / 1_000_000) as i64;
132 let us = timestamp_us % 1_000_000;
133
134 let days = secs / 86_400;
135 let time_of_day = secs % 86_400;
136
137 let hour = time_of_day / 3600;
138 let min = (time_of_day % 3600) / 60;
139 let sec = time_of_day % 60;
140
141 let (y, m, d) = days_to_ymd(days);
142
143 format!("{y:04}-{m:02}-{d:02}T{hour:02}:{min:02}:{sec:02}.{us:06}")
144}
145
146fn write_hex(f: &mut fmt::Formatter<'_>, bytes: &[u8]) -> fmt::Result {
148 write!(f, "[")?;
149 for (i, b) in bytes.iter().enumerate() {
150 if i > 0 {
151 write!(f, " ")?;
152 }
153 write!(f, "{b:02X}")?;
154 }
155 write!(f, "]")
156}
157
158pub(crate) fn days_to_ymd(mut z: i64) -> (i64, u32, u32) {
166 z += 719468;
167 let era = if z >= 0 { z } else { z - 146096 } / 146097;
168 let doe = (z - era * 146097) as u32;
169 let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
170 let y = (yoe as i64) + era * 400;
171 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
172 let mp = (5 * doy + 2) / 153;
173 let d = doy - (153 * mp + 2) / 5 + 1;
174 let m = if mp < 10 { mp + 3 } else { mp - 9 };
175 let y = if m <= 2 { y + 1 } else { y };
176 (y, m, d)
177}
178
179pub struct PacketCapture {
190 records: Mutex<Vec<PacketRecord>>,
191}
192
193impl Default for PacketCapture {
194 fn default() -> Self {
195 Self {
196 records: Mutex::new(Vec::with_capacity(256)),
197 }
198 }
199}
200
201impl PacketCapture {
202 pub fn new() -> Self {
204 Self::default()
205 }
206
207 pub fn drain(&self) -> Vec<PacketRecord> {
209 std::mem::take(&mut *self.records.lock().unwrap_or_else(|e| e.into_inner()))
210 }
211 pub fn len(&self) -> usize {
213 self.records.lock().unwrap_or_else(|e| e.into_inner()).len()
214 }
215 pub fn is_empty(&self) -> bool {
217 self.records
218 .lock()
219 .unwrap_or_else(|e| e.into_inner())
220 .is_empty()
221 }
222
223 fn record(&self, ts: u64, data: PacketData) {
224 self.records
225 .lock()
226 .unwrap_or_else(|e| e.into_inner())
227 .push(PacketRecord {
228 timestamp_us: ts,
229 data,
230 });
231 }
232}
233
234impl WireTap for PacketCapture {
235 fn on_write(&self, bytes: &[u8], ts: u64) {
236 self.record(ts, PacketData::RawTx(bytes.to_vec()));
237 }
238 fn on_read(&self, bytes: &[u8], ts: u64) {
239 self.record(ts, PacketData::RawRx(bytes.to_vec()));
240 }
241 fn on_error(&self, bytes: &[u8], error: &str, ts: u64) {
242 self.record(ts, PacketData::RawError(bytes.to_vec(), error.to_string()));
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
253 fn epoch_zero() {
254 let (y, m, d) = days_to_ymd(0);
255 assert_eq!((y, m, d), (1970, 1, 1));
256 }
257
258 #[test]
259 fn day_one() {
260 let (y, m, d) = days_to_ymd(1);
261 assert_eq!((y, m, d), (1970, 1, 2));
262 }
263
264 #[test]
265 fn day_364_before_year_roll() {
266 let (y, m, d) = days_to_ymd(364);
267 assert_eq!((y, m, d), (1970, 12, 31));
268 }
269
270 #[test]
271 fn day_365_year_roll() {
272 let (y, m, d) = days_to_ymd(365);
273 assert_eq!((y, m, d), (1971, 1, 1));
274 }
275
276 #[test]
277 fn year_2000_jan_1() {
278 let (y, m, d) = days_to_ymd(10957);
282 assert_eq!((y, m, d), (2000, 1, 1));
283 }
284
285 #[test]
286 fn feb_29_leap_year() {
287 let (y, m, d) = days_to_ymd(789);
290 assert_eq!((y, m, d), (1972, 2, 29));
291 }
292
293 #[test]
294 fn year_2026_august() {
295 let (y, m, d) = days_to_ymd(20675);
300 assert_eq!((y, m, d), (2026, 8, 10));
301 }
302
303 #[test]
304 fn far_future_year_2100() {
305 let (y, m, d) = days_to_ymd(47482);
309 assert_eq!((y, m, d), (2100, 1, 1));
310 }
311
312 #[test]
313 fn negative_days_before_epoch() {
314 let (y, m, d) = days_to_ymd(-1);
315 assert_eq!((y, m, d), (1969, 12, 31));
316 }
317}