vanity_ssh_rs/monitor/
progress.rs

1use indicatif::{ProgressBar, ProgressStyle};
2use num_format::{Locale, ToFormattedString};
3use std::sync::mpsc::Receiver;
4use std::time::{Duration, Instant};
5
6use crate::core::pattern::Pattern;
7use crate::core::result::SearchResult;
8use crate::worker::message::WorkerMessage;
9
10pub fn monitor_progress(
11    rx: Receiver<WorkerMessage>,
12    start: Instant,
13    pattern: &Pattern,
14) -> SearchResult {
15    let mut total_attempts = 0;
16    let mut found_key_pair = None;
17
18    let pb = ProgressBar::new_spinner();
19    pb.set_style(
20        ProgressStyle::default_spinner()
21            .template("{spinner:.green} [{elapsed_precise}]\n{msg}")
22            .unwrap(),
23    );
24    pb.enable_steady_tick(Duration::from_millis(100));
25
26    while found_key_pair.is_none() {
27        if let Ok(msg) = rx.recv() {
28            total_attempts += msg.attempts;
29            if let Some(key) = msg.found_key {
30                found_key_pair = Some(key);
31            } else {
32                let duration = start.elapsed();
33                let rate = (total_attempts as f64 / duration.as_secs_f64()).round() as u64;
34
35                let mut progress_msg = format!(
36                    "Attempts: {} ({} keys/sec)",
37                    total_attempts.to_formatted_string(&Locale::en),
38                    rate.to_formatted_string(&Locale::en)
39                );
40
41                if let Some(prob) = pattern.probability() {
42                    let expected_attempts = (1.0 / prob) as u64;
43                    let est_time = pattern
44                        .estimate_time(rate as f64)
45                        .unwrap_or_default()
46                        .split_whitespace()
47                        .take(2)
48                        .collect::<Vec<_>>()
49                        .join(" ");
50
51                    progress_msg = format!(
52                        "{}\nProbability: 1 in {}\nEst. time: {}",
53                        progress_msg,
54                        expected_attempts.to_formatted_string(&Locale::en),
55                        est_time
56                    );
57                }
58
59                pb.set_message(progress_msg);
60            }
61        }
62    }
63
64    pb.finish_and_clear();
65
66    SearchResult {
67        key_pair: found_key_pair.unwrap(),
68        total_attempts,
69        duration: start.elapsed(),
70    }
71}