use std::sync::Arc;
pub trait ProgressHandler: Send + Sync {
fn on_start(&self, component: &str, total_files: usize, total_bytes: u64);
fn on_file_start(&self, file_name: &str, file_size: u64);
fn on_progress(&self, bytes: u64);
fn on_file_complete(&self, file_name: &str, outcome: &str);
fn on_complete(&self, downloaded: usize, skipped: usize);
fn on_error(&self, error: &str);
fn on_message(&self, message: &str) {
let _ = message;
}
}
pub struct IndicatifProgressHandler {
progress_bar: indicatif::ProgressBar,
}
impl IndicatifProgressHandler {
pub fn new(total_bytes: u64) -> Self {
use indicatif::{ProgressBar, ProgressStyle};
let pb = ProgressBar::new(total_bytes);
pb.set_style(
ProgressStyle::default_bar()
.template("{spinner:.green} [{elapsed_precise}] {wide_bar:.cyan/blue} {bytes}/{total_bytes} @ {bytes_per_sec} ETA {eta} | {msg}")
.unwrap()
.progress_chars("##-"),
);
Self { progress_bar: pb }
}
pub fn progress_bar(&self) -> &indicatif::ProgressBar {
&self.progress_bar
}
}
impl ProgressHandler for IndicatifProgressHandler {
fn on_start(&self, component: &str, total_files: usize, total_bytes: u64) {
self.progress_bar.set_message(format!(
"{}: {} files, total {}",
component,
total_files,
humansize::format_size(total_bytes, humansize::BINARY)
));
}
fn on_file_start(&self, file_name: &str, _file_size: u64) {
self.progress_bar.set_message(file_name.to_string());
}
fn on_progress(&self, bytes: u64) {
self.progress_bar.inc(bytes);
}
fn on_file_complete(&self, _file_name: &str, _outcome: &str) {
}
fn on_complete(&self, downloaded: usize, skipped: usize) {
self.progress_bar
.finish_with_message(format!("Done: dl {} | skip {}", downloaded, skipped));
}
fn on_error(&self, error: &str) {
self.progress_bar
.abandon_with_message(format!("Error: {}", error));
}
fn on_message(&self, message: &str) {
self.progress_bar.set_message(message.to_string());
}
}
pub struct NoopProgressHandler;
impl ProgressHandler for NoopProgressHandler {
fn on_start(&self, _component: &str, _total_files: usize, _total_bytes: u64) {}
fn on_file_start(&self, _file_name: &str, _file_size: u64) {}
fn on_progress(&self, _bytes: u64) {}
fn on_file_complete(&self, _file_name: &str, _outcome: &str) {}
fn on_complete(&self, _downloaded: usize, _skipped: usize) {}
fn on_error(&self, _error: &str) {}
}
pub type BoxedProgressHandler = Arc<dyn ProgressHandler>;
pub fn default_progress_handler(total_bytes: u64) -> BoxedProgressHandler {
Arc::new(IndicatifProgressHandler::new(total_bytes))
}
pub fn noop_progress_handler() -> BoxedProgressHandler {
Arc::new(NoopProgressHandler)
}