use clap::{CommandFactory, Parser};
use clap_complete::generate;
use thundra::cli::{Cli, Commands};
use thundra::client::HttpClient;
use thundra::config::{BenchConfig, OutputFormat, RequestSource};
use thundra::executor::Executor;
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let output_format = cli.output;
if let Some(Commands::Completions { shell }) = cli.command {
let mut cmd = Cli::command();
let name = cmd.get_name().to_string();
generate(shell, &mut cmd, name, &mut std::io::stdout());
std::process::exit(0);
}
let config = match BenchConfig::from_args(cli) {
Ok(c) => c,
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
};
let RequestSource::Static(req) = &config.request_source else {
unreachable!("CLI only creates Static requests")
};
eprintln!("Target: {} {:?}", req.url, req.method);
eprintln!("Concurrency: {}", config.concurrency);
eprintln!("Stop condition: {:?}", config.stop_condition);
if let Some(rate) = &config.rate {
eprintln!("Rate limit: {} req/s", rate);
}
let client = match HttpClient::new(config.timeout, config.concurrency, config.insecure) {
Ok(c) => c,
Err(e) => {
eprintln!("Failed to create HTTP client: {}", e);
std::process::exit(1);
}
};
eprintln!(
"\nStarting benchmark with {} workers...",
config.concurrency
);
let (config, pb) = config.with_progress();
let executor = Executor::new(client, config);
match executor.run().await {
Ok(results) => {
pb.finish_and_clear();
match output_format {
OutputFormat::Text => results.print(),
OutputFormat::Json => match serde_json::to_string_pretty(&results) {
Ok(json) => println!("{}", json),
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
},
}
}
Err(e) => {
pb.finish_and_clear();
eprintln!("Benchmark failed: {}", e);
std::process::exit(1);
}
}
}