Skip to main content

twinleaf_tools/cli/
health.rs

1use clap::Parser;
2use std::time::Duration;
3
4use super::nonneg_f64;
5use crate::TioOpts;
6
7#[derive(Parser, Debug, Clone)]
8#[command(
9    version,
10    about = "Live timing & rate diagnostics for TIO (Twinleaf) devices"
11)]
12pub struct HealthCli {
13    #[command(flatten)]
14    pub(crate) tio: TioOpts,
15
16    /// Time window in seconds for calculating jitter statistics
17    #[arg(
18        long = "jitter-window",
19        default_value = "10",
20        value_name = "SECONDS",
21        value_parser = clap::value_parser!(u64).range(1..),
22        help = "Seconds for jitter calculation window (>= 1)"
23    )]
24    pub(crate) jitter_window: u64,
25
26    /// PPM threshold for yellow warning indicators
27    #[arg(
28        long = "ppm-warn",
29        default_value = "100",
30        value_name = "PPM",
31        value_parser = nonneg_f64,
32        help = "Warning threshold in parts per million (>= 0)"
33    )]
34    pub(crate) ppm_warn: f64,
35
36    /// PPM threshold for red error indicators
37    #[arg(
38        long = "ppm-err",
39        default_value = "200",
40        value_name = "PPM",
41        value_parser = nonneg_f64,
42        help = "Error threshold in parts per million (>= 0)"
43    )]
44    pub(crate) ppm_err: f64,
45
46    /// Filter to only show specific stream IDs (comma-separated)
47    #[arg(
48        long = "streams",
49        value_delimiter = ',',
50        value_name = "IDS",
51        value_parser = clap::value_parser!(u8),
52        help = "Comma-separated stream IDs to monitor (e.g., 0,1,5)"
53    )]
54    pub(crate) streams: Option<Vec<u8>>,
55
56    /// Suppress the footer help text
57    #[arg(short = 'q', long = "quiet")]
58    pub(crate) quiet: bool,
59
60    /// UI refresh rate for animations and stale detection (data updates are immediate)
61    #[arg(
62        long = "fps",
63        default_value = "30",
64        value_name = "FPS",
65        value_parser = clap::value_parser!(u64).range(1..=60),
66        help = "UI refresh rate for heartbeat animation and stale detection (1-60)"
67    )]
68    pub(crate) fps: u64,
69
70    /// Time in milliseconds before marking a stream as stale
71    #[arg(
72        long = "stale-ms",
73        default_value = "2000",
74        value_name = "MS",
75        value_parser = clap::value_parser!(u64).range(1..),
76        help = "Mark streams as stale after this many milliseconds without data (>= 1)"
77    )]
78    pub(crate) stale_ms: u64,
79
80    /// Maximum number of events to keep in the event log
81    #[arg(
82        short = 'n',
83        long = "event-log-size",
84        default_value = "100",
85        value_name = "N",
86        value_parser = clap::value_parser!(u64).range(1..),
87        help = "Maximum number of events to keep in history (>= 1)"
88    )]
89    pub(crate) event_log_size: u64,
90
91    /// Number of event lines to display on screen
92    #[arg(
93        long = "event-display-lines",
94        default_value = "8",
95        value_name = "LINES",
96        value_parser = clap::value_parser!(u16).range(3..),
97        help = "Number of event lines to show (>= 3)"
98    )]
99    pub(crate) event_display_lines: u16,
100
101    /// Only show warning and error events in the log
102    #[arg(short = 'w', long = "warnings-only")]
103    pub(crate) warnings_only: bool,
104}
105
106impl HealthCli {
107    pub(crate) fn stale_dur(&self) -> Duration {
108        Duration::from_millis(self.stale_ms)
109    }
110}