@@ -25,6 +25,10 @@ pub struct Cli {
2525 #[ arg( long) ]
2626 pub text : bool ,
2727
28+ /// Run silently: suppress all output except errors (for cron usage)
29+ #[ arg( long) ]
30+ pub silent : bool ,
31+
2832 /// Download phase duration
2933 #[ arg( long, default_value = "10s" ) ]
3034 pub download_duration : humantime:: Duration ,
@@ -95,6 +99,18 @@ pub struct Cli {
9599}
96100
97101pub async fn run ( args : Cli ) -> Result < ( ) > {
102+ // Validate that --silent can only be used with --json
103+ if args. silent && !args. json {
104+ return Err ( anyhow:: anyhow!(
105+ "--silent can only be used with --json. Use --silent --json together."
106+ ) ) ;
107+ }
108+
109+ // Silent mode takes precedence over other output modes
110+ if args. silent {
111+ return run_test_engine ( args, true ) . await ;
112+ }
113+
98114 if !args. json && !args. text {
99115 #[ cfg( feature = "tui" ) ]
100116 {
@@ -108,7 +124,7 @@ pub async fn run(args: Cli) -> Result<()> {
108124 }
109125
110126 if args. json {
111- return run_json ( args) . await ;
127+ return run_test_engine ( args, false ) . await ;
112128 }
113129
114130 run_text ( args) . await
@@ -143,29 +159,63 @@ pub fn build_config(args: &Cli) -> RunConfig {
143159 }
144160}
145161
146- async fn run_json ( args : Cli ) -> Result < ( ) > {
162+ /// Common function to run the test engine and process results.
163+ /// `silent` controls whether to consume events and suppress output.
164+ async fn run_test_engine ( args : Cli , silent : bool ) -> Result < ( ) > {
147165 let cfg = build_config ( & args) ;
148- let ( evt_tx, _) = mpsc:: channel :: < TestEvent > ( 1024 ) ;
149- let ( _, ctrl_rx) = mpsc:: channel :: < EngineControl > ( 16 ) ;
166+ let network_info = crate :: network:: gather_network_info ( & args) ;
167+ let enriched = if silent {
168+ // In silent mode, spawn task and consume events
169+ let ( evt_tx, mut evt_rx) = mpsc:: channel :: < TestEvent > ( 2048 ) ;
170+ let ( _, ctrl_rx) = mpsc:: channel :: < EngineControl > ( 16 ) ;
150171
151- let engine = TestEngine :: new ( cfg) ;
152- let result = engine
153- . run ( evt_tx, ctrl_rx)
154- . await
155- . context ( "speed test failed" ) ?;
172+ let engine = TestEngine :: new ( cfg) ;
173+ let handle = tokio:: spawn ( async move { engine. run ( evt_tx, ctrl_rx) . await } ) ;
156174
157- // Gather network information and enrich result
158- let network_info = crate :: network:: gather_network_info ( & args) ;
159- let enriched = crate :: network:: enrich_result ( & result, & network_info) ;
175+ // Consume events silently (no output)
176+ while let Some ( _ev) = evt_rx. recv ( ) . await {
177+ // All events are silently consumed - no output
178+ }
179+
180+ let result = handle
181+ . await
182+ . context ( "test engine task failed" ) ?
183+ . context ( "speed test failed" ) ?;
184+
185+ crate :: network:: enrich_result ( & result, & network_info)
186+ } else {
187+ // In JSON mode, directly await the engine (no need to consume events)
188+ let ( evt_tx, _) = mpsc:: channel :: < TestEvent > ( 1024 ) ;
189+ let ( _, ctrl_rx) = mpsc:: channel :: < EngineControl > ( 16 ) ;
160190
191+ let engine = TestEngine :: new ( cfg) ;
192+ let result = engine
193+ . run ( evt_tx, ctrl_rx)
194+ . await
195+ . context ( "speed test failed" ) ?;
196+
197+ crate :: network:: enrich_result ( & result, & network_info)
198+ } ;
199+
200+ // Handle exports (errors will propagate)
161201 handle_exports ( & args, & enriched) ?;
162202
163- println ! ( "{}" , serde_json:: to_string_pretty( & enriched) ?) ;
203+ if !silent {
204+ // Print JSON output in non-silent mode
205+ println ! ( "{}" , serde_json:: to_string_pretty( & enriched) ?) ;
206+ }
207+
208+ // Save results if auto_save is enabled
164209 if args. auto_save {
165- if let Ok ( p) = crate :: storage:: save_run ( & enriched) {
166- eprintln ! ( "Saved: {}" , p. display( ) ) ;
210+ if silent {
211+ crate :: storage:: save_run ( & enriched) . context ( "failed to save run results" ) ?;
212+ } else {
213+ if let Ok ( p) = crate :: storage:: save_run ( & enriched) {
214+ eprintln ! ( "Saved: {}" , p. display( ) ) ;
215+ }
167216 }
168217 }
218+
169219 Ok ( ( ) )
170220}
171221
0 commit comments