1use clap::{Args, Parser, Subcommand};
2
3use crate::speedtest::TestDuration;
4
5#[derive(Parser)]
7#[command(
8 name = "nd300",
9 author,
10 version,
11 disable_version_flag = true,
12 about = "ND-300 Network Diagnostic - QubeTX Developer Tools",
13 long_about = "ND-300 Network Diagnostic - QubeTX Developer Tools\n\n\
14 Cross-platform network diagnostics with 25+ concurrent checks,\n\
15 multi-stage network repair, and DNS configuration management.",
16 after_long_help = "EXAMPLES:\n\
17 \x20 nd300 Run standard diagnostics\n\
18 \x20 nd300 -t Technician mode (deep diagnostics)\n\
19 \x20 nd300 dns Change DNS servers and verify connectivity\n\
20 \x20 nd300 -d Same as 'nd300 dns' (legacy flag form)\n\
21 \x20 nd300 fix Diagnostic-driven triage and recovery loop\n\
22 \x20 nd300 -f Same as 'nd300 fix' (legacy flag form)\n\
23 \x20 nd300 update Check for updates and install\n\
24 \x20 nd300 clear-dns Reset DNS cache\n\
25 \x20 nd300 uninstall Remove nd300 from this system\n\
26 \x20 nd300 --fast Skip speed test for faster execution\n\
27 \x20 nd300 --json Output results as JSON\n\n\
28 Run 'nd300 --help' for full details, or 'nd300 -h' for a summary."
29)]
30pub struct Nd300Cli {
31 #[arg(
33 short = 't',
34 long = "tech",
35 alias = "technician",
36 help_heading = "Modes",
37 global = true
38 )]
39 pub tech: bool,
40
41 #[arg(short = 'T', long, help_heading = "Modes", global = true)]
43 pub title: Option<String>,
44
45 #[arg(long, help_heading = "Output", global = true)]
47 pub json: bool,
48
49 #[arg(long, help_heading = "Output", global = true)]
51 pub ascii: bool,
52
53 #[arg(long, help_heading = "Output", global = true)]
55 pub no_color: bool,
56
57 #[arg(long, help_heading = "Output", global = true)]
59 pub verbose: bool,
60
61 #[arg(long, help_heading = "Speed Test", global = true)]
63 pub fast: bool,
64
65 #[arg(long, default_value = "10", help_heading = "Speed Test", global = true)]
67 pub speed_duration: u64,
68
69 #[arg(short = 'd', long = "dns", help_heading = "Actions")]
71 pub dns: bool,
72
73 #[arg(short = 'f', long = "fix", help_heading = "Actions")]
75 pub fix: bool,
76
77 #[arg(short = 'c', long = "clear-dns", help_heading = "Actions")]
79 pub clear_dns: bool,
80
81 #[arg(long = "uninstall", help_heading = "Actions")]
83 pub uninstall: bool,
84
85 #[arg(long = "update", help_heading = "Actions")]
87 pub update: bool,
88
89 #[arg(
92 short = 'y',
93 long = "yes",
94 alias = "non-interactive",
95 help_heading = "Actions",
96 global = true
97 )]
98 pub yes: bool,
99
100 #[arg(short = 'v', long = "version", action = clap::ArgAction::Version)]
102 pub version: (),
103
104 #[command(subcommand)]
106 pub command: Option<Nd300Command>,
107}
108
109#[derive(Subcommand, Debug, Clone)]
114pub enum Nd300Command {
115 Fix(FixArgs),
120
121 Dns,
124
125 Update,
127
128 #[command(name = "clear-dns")]
130 ClearDns,
131
132 Uninstall,
134}
135
136#[derive(Args, Debug, Clone, Default)]
142pub struct FixArgs {}
143
144#[derive(Parser)]
148#[command(
149 name = "speedqx",
150 author,
151 version,
152 disable_version_flag = true,
153 about = "SpeedQX Internet Speed Test - QubeTX Developer Tools",
154 long_about = "SpeedQX Internet Speed Test - QubeTX Developer Tools\n\n\
155 Quad-provider speed test using Cloudflare, M-Lab NDT7, LibreSpeed, and fast.com (Netflix).\n\
156 All four providers run and results are aggregated for maximum accuracy.",
157 after_long_help = "EXAMPLES:\n\
158 \x20 speedqx Run full speed test (all 4 providers)\n\
159 \x20 speedqx --duration 60 60s per direction for CF/NDT7/LS\n\
160 \x20 speedqx --fastcom-duration 30 Override fast.com to 30s/dir\n\
161 \x20 speedqx update Check for updates and install\n\
162 \x20 speedqx --update Same as 'speedqx update' (legacy flag form)\n\
163 \x20 speedqx --json Output results as JSON\n\n\
164 Run 'speedqx --help' for full details, or 'speedqx -h' for a summary."
165)]
166pub struct SpeedQXCli {
167 #[arg(long, help_heading = "Output", global = true)]
169 pub json: bool,
170
171 #[arg(long, help_heading = "Output", global = true)]
173 pub ascii: bool,
174
175 #[arg(long, help_heading = "Output", global = true)]
177 pub no_color: bool,
178
179 #[arg(
181 long,
182 default_value = "30",
183 value_parser = parse_duration,
184 help_heading = "Speed Test"
185 )]
186 pub duration: TestDuration,
187
188 #[arg(
190 long,
191 default_value = "auto",
192 value_parser = parse_duration,
193 help_heading = "Speed Test"
194 )]
195 pub fastcom_duration: TestDuration,
196
197 #[arg(long, default_value = "20", help_heading = "Speed Test")]
199 pub latency_probes: u32,
200
201 #[arg(long = "update", help_heading = "Actions")]
203 pub update: bool,
204
205 #[arg(short = 'v', long = "version", action = clap::ArgAction::Version)]
207 pub version: (),
208
209 #[command(subcommand)]
211 pub command: Option<SpeedQXCommand>,
212}
213
214#[derive(Subcommand, Debug, Clone)]
217pub enum SpeedQXCommand {
218 Update,
220}
221
222fn parse_duration(s: &str) -> Result<TestDuration, String> {
223 if s.eq_ignore_ascii_case("auto") {
224 Ok(TestDuration::Auto)
225 } else {
226 s.parse::<u64>()
227 .map(TestDuration::Seconds)
228 .map_err(|_| format!("invalid duration '{}': expected a number or \"auto\"", s))
229 }
230}