mod getstate;
use atty::Stream;
use getstate::GetState;
use std::env;
use std::io::{self, BufRead};
fn get_human_readable_time(time: u64) -> chrono::NaiveDateTime {
chrono::NaiveDateTime::from_timestamp((time / 1000) as i64, 0)
}
fn get_stdio_lines() -> Vec<String> {
let stdin = io::stdin();
let lines = stdin.lock().lines();
let mut lines_vec = Vec::new();
for line in lines {
let line_unwrap = line.unwrap();
if line_unwrap.starts_with("https://") || line_unwrap.starts_with("http://") {
let actual = line_unwrap.clone();
lines_vec.push(actual);
} else {
let actual = line_unwrap.clone();
lines_vec.push(format!("http://{}", actual));
lines_vec.push(format!("https://{}", actual));
}
}
lines_vec
}
fn check_for_stdin() {
if atty::is(Stream::Stdin) {
print_help();
std::process::exit(0);
}
}
fn get_now() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap().as_millis() as u64
}
fn print_prg_info() {
let prg_info = format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
let prg_authors = format!("(c) 2022 by {}", env!("CARGO_PKG_AUTHORS"));
let prg_description = format!("{}", env!("CARGO_PKG_DESCRIPTION"));
println!("{} {}", prg_info, prg_authors);
println!("{}", prg_description);
println!("");
}
fn print_help() {
print_prg_info();
println!("Usage: cat domains.txt | rprobe [options]");
println!("Options:");
println!(" -h, --help\t\t\tPrint this help");
println!(" -v, --version\t\t\tPrint version information");
println!(" -t, --timeout\t\t\tSet timeout in seconds (default: 10)");
println!("");
}
#[tokio::main]
async fn main() {
let mut tokio_state = GetState::new();
let mut timeout = 10;
check_for_stdin();
let args: Vec<String> = env::args().collect();
for (index, arg) in args.iter().enumerate() {
if arg == "-t" || arg == "--timeout" {
timeout = args[index + 1].parse::<u64>().unwrap();
} else if (arg == "-h" || arg == "--help") && args.len() == 2 {
print_help();
std::process::exit(0);
} else if (arg == "-v" || arg == "--version") && args.len() == 2 {
print_prg_info();
std::process::exit(0);
}
}
let lines_vec = get_stdio_lines();
tokio_state.total_requests = lines_vec.len() as u64;
tokio_state.start_time = get_now();
let mut tasks = Vec::new();
for line in lines_vec {
let task = tokio::spawn(async move {
let client = reqwest::Client::new();
let res = client.get(&line)
.timeout(std::time::Duration::from_secs(timeout))
.send().await;
match res {
Ok(_) => {
println!("{}", line);
return true;
}
Err(_) => {
return false;
}
}
});
tasks.push(task);
}
for task in tasks {
let rval = task.await.unwrap();
if rval {
tokio_state.add_success();
} else {
tokio_state.add_failure();
}
}
tokio_state.end_time = get_now();
println!("");
println!("{} requests. Started at {} / Ended at {}. {} ms. Successful: {}. Failed: {}.", tokio_state.total_requests, get_human_readable_time(tokio_state.start_time), get_human_readable_time(tokio_state.end_time), tokio_state.end_time - tokio_state.start_time, tokio_state.successful_requests, tokio_state.failed_requests);
}