Skip to main content

netpulse/
state.rs

1// src/state.rs — Shared application state
2//
3// AppState is the single source of truth shared between:
4// - Prober tasks (write: push ProbeResult, update seq/last_rtt)
5// - TUI renderer (read: sparkline data, stats, status)
6// - Stream exporter (read: stats snapshots)
7//
8// Wrapped in Arc<Mutex<>> for safe cross-task sharing.
9// Lock contention is minimal — probers write once per interval (≥ 100ms),
10// TUI reads once per render frame (~100ms).
11
12use crate::stats::ring_buffer::RingBuffer;
13use std::collections::HashMap;
14use std::sync::{Arc, Mutex};
15
16/// Per-target probe state.
17pub struct TargetState {
18    /// Original display name (e.g., "google.com" or "8.8.8.8")
19    pub display_name: String,
20    /// Resolved IP address used for ICMP probing
21    pub resolved_addr: String,
22    /// Ring buffer of recent probe results
23    pub buffer: RingBuffer,
24    /// Total probes sent (used as sequence counter)
25    pub seq: u64,
26    /// RTT of the most recent probe in microseconds; None = loss
27    pub last_rtt_us: Option<u64>,
28    /// Latest responder IP address (used primarily in trace mode)
29    pub last_ip: Option<String>,
30}
31
32impl TargetState {
33    pub fn new(display_name: &str, resolved_addr: &str, window: usize) -> Self {
34        Self {
35            display_name: display_name.to_string(),
36            resolved_addr: resolved_addr.to_string(),
37            buffer: RingBuffer::new(window),
38            seq: 0,
39            last_rtt_us: None,
40            last_ip: None,
41        }
42    }
43
44    pub fn new_hop(window: usize) -> Self {
45        Self {
46            display_name: String::new(),
47            resolved_addr: String::new(),
48            buffer: RingBuffer::new(window),
49            seq: 0,
50            last_rtt_us: None,
51            last_ip: None,
52        }
53    }
54}
55
56/// Shared application state: one entry per monitored target.
57pub type AppState = Arc<Mutex<HashMap<String, TargetState>>>;
58
59/// Create a new empty AppState.
60pub fn new_app_state() -> AppState {
61    Arc::new(Mutex::new(HashMap::new()))
62}