| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- use crate::types::{DomainResult, DomainStatus, ErrorKind};
- use colored::*;
- use std::io::Write;
- use std::path::PathBuf;
- pub fn print_available_table(results: &[DomainResult], no_color: bool, no_unicode: bool) {
- let available: Vec<&DomainResult> = results.iter().filter(|r| r.is_available()).collect();
- if available.is_empty() {
- println!("No available domains found.");
- return;
- }
- let max_len = available.iter().map(|r| r.full.len()).max().unwrap_or(20);
- let width = max_len + 4; // padding
- let title = "Available Domains";
- let title_padded = format!("{:^width$}", title, width = width);
- if no_unicode {
- // ASCII box
- let border = format!("+{}+", "-".repeat(width));
- println!("{}", border);
- if no_color {
- println!("|{}|", title_padded);
- } else {
- println!("|{}|", title_padded.green());
- }
- println!("+{}+", "-".repeat(width));
- for r in &available {
- println!("| {:<pad$} |", r.full, pad = width - 2);
- }
- println!("{}", border);
- } else {
- // Unicode box
- let top = format!("┌{}┐", "─".repeat(width));
- let sep = format!("├{}┤", "─".repeat(width));
- let bot = format!("└{}┘", "─".repeat(width));
- println!("{}", top);
- if no_color {
- println!("│{}│", title_padded);
- } else {
- println!("│{}│", title_padded.green());
- }
- println!("{}", sep);
- for r in &available {
- println!("│ {:<pad$} │", r.full, pad = width - 2);
- }
- println!("{}", bot);
- }
- }
- pub fn print_full_table(results: &[DomainResult], no_color: bool, no_unicode: bool) {
- if results.is_empty() {
- println!("No results.");
- return;
- }
- // calc column widths
- let domain_w = results
- .iter()
- .map(|r| r.full.len())
- .max()
- .unwrap_or(10)
- .max(7);
- let status_w = 10; // "registered" is the longest
- let note_w = results
- .iter()
- .map(|r| r.note_str().len())
- .max()
- .unwrap_or(4)
- .max(4);
- let domain_col = domain_w + 2;
- let status_col = status_w + 2;
- let note_col = note_w + 2;
- if no_unicode {
- print_full_table_ascii(results, domain_col, status_col, note_col, no_color);
- } else {
- print_full_table_unicode(results, domain_col, status_col, note_col, no_color);
- }
- }
- fn print_full_table_unicode(
- results: &[DomainResult],
- dc: usize,
- sc: usize,
- nc: usize,
- no_color: bool,
- ) {
- let top = format!("┌{}┬{}┬{}┐", "─".repeat(dc), "─".repeat(sc), "─".repeat(nc));
- let sep = format!("├{}┼{}┼{}┤", "─".repeat(dc), "─".repeat(sc), "─".repeat(nc));
- let bot = format!("└{}┴{}┴{}┘", "─".repeat(dc), "─".repeat(sc), "─".repeat(nc));
- println!("{}", top);
- println!(
- "│{:^dc$}│{:^sc$}│{:^nc$}│",
- "Domains",
- "Status",
- "Note",
- dc = dc,
- sc = sc,
- nc = nc,
- );
- println!("{}", sep);
- for r in results {
- let domain_str = format!(" {:<width$} ", r.full, width = dc - 2);
- let status_str = format!(" {:<width$} ", r.status_str(), width = sc - 2);
- let note_str = format!(" {:<width$} ", r.note_str(), width = nc - 2);
- if no_color {
- println!("│{}│{}│{}│", domain_str, status_str, note_str);
- } else {
- let colored_domain = color_domain(&domain_str, &r.status);
- println!("│{}│{}│{}│", colored_domain, status_str, note_str);
- }
- }
- println!("{}", bot);
- }
- fn print_full_table_ascii(
- results: &[DomainResult],
- dc: usize,
- sc: usize,
- nc: usize,
- no_color: bool,
- ) {
- let border = format!("+{}+{}+{}+", "-".repeat(dc), "-".repeat(sc), "-".repeat(nc));
- println!("{}", border);
- println!(
- "|{:^dc$}|{:^sc$}|{:^nc$}|",
- "Domains",
- "Status",
- "Note",
- dc = dc,
- sc = sc,
- nc = nc,
- );
- println!("{}", border);
- for r in results {
- let domain_str = format!(" {:<width$} ", r.full, width = dc - 2);
- let status_str = format!(" {:<width$} ", r.status_str(), width = sc - 2);
- let note_str = format!(" {:<width$} ", r.note_str(), width = nc - 2);
- if no_color {
- println!("|{}|{}|{}|", domain_str, status_str, note_str);
- } else {
- let colored_domain = color_domain(&domain_str, &r.status);
- println!("|{}|{}|{}|", colored_domain, status_str, note_str);
- }
- }
- println!("{}", border);
- }
- fn color_domain(domain: &str, status: &DomainStatus) -> ColoredString {
- match status {
- DomainStatus::Available => domain.green(),
- DomainStatus::Registered { .. } => domain.red(),
- DomainStatus::Error { kind, .. } => match kind {
- ErrorKind::InvalidTld => domain.yellow(),
- _ => domain.blue(),
- },
- }
- }
- pub fn print_csv(results: &[DomainResult]) {
- println!("Domains, Status, Note");
- for r in results {
- println!("{}, {}, {}", r.full, r.status_str(), r.note_str());
- }
- }
- pub fn write_csv_file(results: &[DomainResult], path: &PathBuf) -> Result<(), String> {
- let mut file =
- std::fs::File::create(path).map_err(|e| format!("Could not create CSV file: {}", e))?;
- writeln!(file, "Domains, Status, Note").map_err(|e| format!("Write error: {}", e))?;
- for r in results {
- writeln!(file, "{}, {}, {}", r.full, r.status_str(), r.note_str())
- .map_err(|e| format!("Write error: {}", e))?;
- }
- Ok(())
- }
- pub fn print_errors(results: &[DomainResult], verbose: bool) {
- for r in results {
- if let DomainStatus::Error { kind, message } = &r.status {
- match kind {
- ErrorKind::InvalidTld => {
- eprintln!("Error for {}, tld does not seem to exist", r.full);
- }
- _ => {
- if verbose {
- eprintln!("Error for {}, {} (raw: {})", r.full, message, message);
- } else {
- eprintln!(
- "Error for {}, unknown error (enable verbose to see raw error)",
- r.full
- );
- }
- }
- }
- }
- }
- }
- pub fn print_progress(current: usize, total: usize) {
- use std::sync::Mutex;
- use std::time::Instant;
- static START: Mutex<Option<Instant>> = Mutex::new(None);
- let mut lock = START.lock().unwrap();
- let start = *lock.get_or_insert_with(Instant::now);
- let percent = (current as f64 / total as f64 * 100.0) as u32;
- eprint!("\rParsing results : {}%", percent);
- if current == total {
- let secs = start.elapsed().as_secs_f64();
- eprintln!("\rParsing results : Done (Took {:.1}s) ", secs);
- *lock = None; // reset for next search duh
- }
- }
|