Refactored redis component to use a centralized postgres database with coordinator instead of descentralized sqlite shitty databases
This commit is contained in:
+165
@@ -1,5 +1,7 @@
|
||||
use std::io::{self, IsTerminal, Write};
|
||||
use std::sync::Mutex;
|
||||
use std::time::Duration;
|
||||
use terminal_size::{terminal_size, Width};
|
||||
|
||||
pub const BANNER: [&str; 9] = [
|
||||
" ░██████ ░██████ ",
|
||||
@@ -25,6 +27,23 @@ pub struct TerminalUi {
|
||||
lock: Mutex<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RedisWorkerScreenState {
|
||||
pub worker_name: String,
|
||||
pub queue_name: String,
|
||||
pub current_ip: String,
|
||||
pub current_path: String,
|
||||
pub current_status: String,
|
||||
pub processed: usize,
|
||||
pub captured: usize,
|
||||
pub global_done: usize,
|
||||
pub global_total: usize,
|
||||
pub queue_remaining: Option<usize>,
|
||||
pub block_done: usize,
|
||||
pub block_total: usize,
|
||||
pub elapsed: Duration,
|
||||
}
|
||||
|
||||
impl TerminalUi {
|
||||
pub fn new(enabled: bool) -> Self {
|
||||
Self {
|
||||
@@ -56,6 +75,104 @@ impl TerminalUi {
|
||||
let _ = stdout.flush();
|
||||
}
|
||||
|
||||
pub fn render_redis_worker(&self, state: &RedisWorkerScreenState) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let _guard = self.lock.lock().expect("terminal mutex poisoned");
|
||||
let mut stdout = io::stdout();
|
||||
let width = terminal_width();
|
||||
let content_width = width.saturating_sub(2).max(32);
|
||||
let global_percent = percent(state.global_done, state.global_total);
|
||||
let block_percent = percent(state.block_done, state.block_total);
|
||||
let global_bar = progress_bar(global_percent, content_width.saturating_sub(24));
|
||||
let block_bar = progress_bar(block_percent, content_width.saturating_sub(24));
|
||||
let queue_remaining = state
|
||||
.queue_remaining
|
||||
.map(|value| value.to_string())
|
||||
.unwrap_or_else(|| "?".to_string());
|
||||
|
||||
let _ = write!(stdout, "\x1b[2J\x1b[H\x1b[?25l");
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(
|
||||
&format!(
|
||||
"CamFinder Redis Worker {} pid:{}",
|
||||
state.worker_name,
|
||||
std::process::id()
|
||||
),
|
||||
content_width
|
||||
)
|
||||
);
|
||||
let _ = writeln!(stdout, "{}", "─".repeat(content_width));
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(&format!("Fila: {}", state.queue_name), content_width)
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(
|
||||
&format!(
|
||||
"Global: [{}] {:>5.1}% {}/{} IPs redis:{}",
|
||||
global_bar,
|
||||
global_percent,
|
||||
state.global_done,
|
||||
state.global_total,
|
||||
queue_remaining
|
||||
),
|
||||
content_width
|
||||
)
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(
|
||||
&format!(
|
||||
"Bloco : [{}] {:>5.1}% {}/{} tentativas",
|
||||
block_bar, block_percent, state.block_done, state.block_total
|
||||
),
|
||||
content_width
|
||||
)
|
||||
);
|
||||
let _ = writeln!(stdout, "{}", "─".repeat(content_width));
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(&format!("IP atual : {}", state.current_ip), content_width)
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(&format!("Path : {}", state.current_path), content_width)
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(
|
||||
&format!("Status : {}", state.current_status),
|
||||
content_width
|
||||
)
|
||||
);
|
||||
let _ = writeln!(
|
||||
stdout,
|
||||
"{}",
|
||||
fit_line(
|
||||
&format!(
|
||||
"Tentativas: {} Capturas: {} Tempo: {}",
|
||||
state.processed,
|
||||
state.captured,
|
||||
format_duration(state.elapsed)
|
||||
),
|
||||
content_width
|
||||
)
|
||||
);
|
||||
let _ = stdout.flush();
|
||||
}
|
||||
|
||||
pub fn render(&self, state: &ScreenState) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
@@ -97,3 +214,51 @@ impl TerminalUi {
|
||||
pub fn stdout_is_terminal() -> bool {
|
||||
io::stdout().is_terminal()
|
||||
}
|
||||
|
||||
fn terminal_width() -> usize {
|
||||
terminal_size()
|
||||
.map(|(Width(width), _)| usize::from(width))
|
||||
.unwrap_or(80)
|
||||
}
|
||||
|
||||
fn percent(done: usize, total: usize) -> f64 {
|
||||
if total == 0 {
|
||||
0.0
|
||||
} else {
|
||||
((done as f64 / total as f64) * 100.0).clamp(0.0, 100.0)
|
||||
}
|
||||
}
|
||||
|
||||
fn progress_bar(percent: f64, width: usize) -> String {
|
||||
let width = width.clamp(8, 80);
|
||||
let filled = ((percent / 100.0) * width as f64).round() as usize;
|
||||
let empty = width.saturating_sub(filled);
|
||||
format!("{}{}", "█".repeat(filled), "░".repeat(empty))
|
||||
}
|
||||
|
||||
fn fit_line(value: &str, width: usize) -> String {
|
||||
let chars = value.chars().collect::<Vec<_>>();
|
||||
if chars.len() <= width {
|
||||
return value.to_string();
|
||||
}
|
||||
if width <= 1 {
|
||||
return "…".to_string();
|
||||
}
|
||||
chars
|
||||
.into_iter()
|
||||
.take(width - 1)
|
||||
.chain(std::iter::once('…'))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn format_duration(duration: Duration) -> String {
|
||||
let total = duration.as_secs();
|
||||
let hours = total / 3600;
|
||||
let minutes = (total % 3600) / 60;
|
||||
let seconds = total % 60;
|
||||
if hours > 0 {
|
||||
format!("{hours:02}:{minutes:02}:{seconds:02}")
|
||||
} else {
|
||||
format!("{minutes:02}:{seconds:02}")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user