use std::io::{self, IsTerminal, Write}; use std::sync::Mutex; pub const BANNER: [&str; 9] = [ " ░██████ ░██████ ", " ░██ ░██ ░██ ░██ ", "░██ ░██████ ░█████████████░██ ░███████ ░██████ ░████████ ░████████ ░███████ ░██░████ ", "░██ ░██░██ ░██ ░██░████████░██ ░██ ░██ ░██ ░██░██ ░██░██ ░██░███ ", "░██ ░███████░██ ░██ ░██ ░██░██ ░███████ ░██ ░██░██ ░██░█████████░██ ", " ░██ ░██░██ ░██░██ ░██ ░██░██ ░██░██ ░██░██ ░██░██ ░██░██ ░██░██ ░██ ", " ░██████ ░█████░█░██ ░██ ░██ ░██████ ░███████ ░█████░██░██ ░██░██ ░██ ░███████ ░██ ", " ", " ", ]; #[derive(Debug, Clone)] pub struct ScreenState { pub current_ip: String, pub tested: usize, pub total: usize, } pub struct TerminalUi { enabled: bool, lock: Mutex<()>, } impl TerminalUi { pub fn new(enabled: bool) -> Self { Self { enabled, lock: Mutex::new(()), } } pub fn is_enabled(&self) -> bool { self.enabled } pub fn print_banner(&self) { if !self.enabled { return; } let _guard = self.lock.lock().expect("terminal mutex poisoned"); let mut stdout = io::stdout(); let _ = write!(stdout, "\x1b[2J\x1b[H\x1b[?25l"); for line in BANNER { let _ = writeln!(stdout, "{line}"); } let _ = writeln!(stdout, "IP: aguardando..."); let _ = writeln!( stdout, "Progress: [░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░] | 0.0%" ); let _ = stdout.flush(); } pub fn render(&self, state: &ScreenState) { if !self.enabled { return; } let _guard = self.lock.lock().expect("terminal mutex poisoned"); let mut stdout = io::stdout(); let percent = if state.total == 0 { 100.0 } else { ((state.tested as f64 / state.total as f64) * 100.0).min(100.0) }; let bar_width = 36usize; let filled = ((percent / 100.0) * bar_width as f64).round() as usize; let empty = bar_width.saturating_sub(filled); let bar = format!("{}{}", "█".repeat(filled), "░".repeat(empty)); let ip = format!("{:<15}", state.current_ip); let percent = format!("{:>5.1}%", percent); let _ = write!( stdout, "\x1b[2F\x1b[2KIP: {ip}\n\x1b[2KProgress: [{bar}] | {percent}\n" ); let _ = stdout.flush(); } pub fn finish(&self) { if !self.enabled { return; } let _guard = self.lock.lock().expect("terminal mutex poisoned"); let mut stdout = io::stdout(); let _ = write!(stdout, "\x1b[?25h"); let _ = stdout.flush(); } } pub fn stdout_is_terminal() -> bool { io::stdout().is_terminal() }