pub mod cli;
pub mod error;
pub mod http;
pub mod perf;
use clap::Parser;
use std::time::Duration;
use colored::Colorize;
use cli::Cli;
use error::Result;
use http::{HttpClient, HttpRequest};
use perf::{Dataset, PerfRunner, PerfReport};
#[tokio::main]
async fn main() {
if let Err(e) = run().await {
eprintln!("{} {}", "Error:".red().bold(), e);
std::process::exit(1);
}
}
async fn run() -> Result<()> {
let cli = Cli::parse();
let mut request = HttpRequest::new(&cli.url)
.method(&cli.method)?
.headers_from_strings(&cli.headers)?
.timeout(Duration::from_secs(cli.timeout))
.follow_redirects(cli.follow_redirects);
if let Some(data) = &cli.data {
request = request.body(data.clone());
} else if let Some(file) = &cli.body_file {
request = request.body_from_file(file)?;
}
if cli.is_perf_mode() {
run_perf_test(&cli, request).await?;
} else {
run_single_request(&cli, request).await?;
}
Ok(())
}
async fn run_single_request(cli: &Cli, request: HttpRequest) -> Result<()> {
let client = HttpClient::new(cli.verbose);
let response = client.execute(&request).await?;
response.print(cli.include_headers, cli.verbose);
Ok(())
}
async fn run_perf_test(cli: &Cli, base_request: HttpRequest) -> Result<()> {
println!("{}", "🚀 Starting Performance Test".cyan().bold());
println!(" URL: {}", cli.url.yellow());
println!(" Concurrency: {}", cli.concurrency);
println!(" Total Requests: {}", cli.total_requests);
println!();
let dataset = if let Some(file) = &cli.perf_file {
println!(" Dataset: {}", file.display().to_string().yellow());
Dataset::from_file(file)?
} else {
Dataset::simple(cli.total_requests)
};
let runner = PerfRunner::new(
cli.url.clone(),
base_request,
cli.concurrency,
cli.total_requests,
cli.verbose,
);
let metrics = runner.run(&dataset).await?;
PerfReport::print(&metrics, &cli.output_format);
Ok(())
}