rework main signature + impl builder for optimizer
This commit is contained in:
parent
02d9d60686
commit
5575392f73
@ -195,7 +195,7 @@ pub struct Directory {
|
|||||||
impl Directory {
|
impl Directory {
|
||||||
pub fn from_path(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
pub fn from_path(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
if !std::path::Path::new(path).is_dir() {
|
if !std::path::Path::new(path).is_dir() {
|
||||||
return Err(format!("Directory path: {} must be a directory", path).into());
|
return Err(format!("directory path: {} must be a directory", path).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut nb_files = 0;
|
let mut nb_files = 0;
|
||||||
|
|||||||
24
src/main.rs
24
src/main.rs
@ -1,3 +1,5 @@
|
|||||||
|
use std::process::exit;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
|
|
||||||
@ -22,17 +24,29 @@ struct Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() {
|
||||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let directory = Directory::from_path(&args.src)?;
|
let directory = match Directory::from_path(&args.src) {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"unable to load directory from path: {}, details: {}",
|
||||||
|
args.src,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let optimizer = ImgOptimizer::new(&args.dest, args.workers);
|
let optimizer = ImgOptimizer::builder(&args.dest, args.workers)
|
||||||
|
.with_progress()
|
||||||
|
.build();
|
||||||
let file_group =
|
let file_group =
|
||||||
directory.get_file_group(Some(FileImgMimetype::Jpeg), Some(FileSizeRange::Tiny));
|
directory.get_file_group(Some(FileImgMimetype::Jpeg), Some(FileSizeRange::Tiny));
|
||||||
|
|
||||||
let result = optimizer.optimize(&file_group).await?;
|
let result = optimizer.optimize(&file_group).await;
|
||||||
let (optimized, percent, size) = result.stats();
|
let (optimized, percent, size) = result.stats();
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
@ -41,6 +55,4 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
percent,
|
percent,
|
||||||
size
|
size
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,17 +133,49 @@ pub struct ImgOptimizer {
|
|||||||
queue: Arc<Queue<File>>,
|
queue: Arc<Queue<File>>,
|
||||||
cancel_token: CancellationToken,
|
cancel_token: CancellationToken,
|
||||||
tracker: TaskTracker,
|
tracker: TaskTracker,
|
||||||
|
progress: Arc<ProgressBar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImgOptimizer {
|
pub struct ImgOptimizerBuilder(ImgOptimizer);
|
||||||
|
|
||||||
|
impl ImgOptimizerBuilder {
|
||||||
pub fn new(dest_dir: &str, nb_workers: usize) -> Self {
|
pub fn new(dest_dir: &str, nb_workers: usize) -> Self {
|
||||||
ImgOptimizer {
|
ImgOptimizerBuilder(ImgOptimizer {
|
||||||
dest_dir: dest_dir.to_string(),
|
dest_dir: dest_dir.to_string(),
|
||||||
nb_workers,
|
nb_workers,
|
||||||
queue: Arc::new(Queue::new()),
|
queue: Arc::new(Queue::new()),
|
||||||
cancel_token: CancellationToken::new(),
|
cancel_token: CancellationToken::new(),
|
||||||
tracker: TaskTracker::new(),
|
tracker: TaskTracker::new(),
|
||||||
|
progress: Arc::new(ProgressBar::hidden()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_progress(mut self) -> Self {
|
||||||
|
let pb = Arc::new(ProgressBar::new(0));
|
||||||
|
|
||||||
|
let tmpl_res =
|
||||||
|
ProgressStyle::default_bar().template("{msg} [{bar:40}] {pos}/{len} ({eta})");
|
||||||
|
|
||||||
|
if let Err(e) = tmpl_res {
|
||||||
|
log::error!("unable to set the progress bar, {}", e);
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let style = tmpl_res.unwrap().progress_chars("##-");
|
||||||
|
pb.set_style(style);
|
||||||
|
|
||||||
|
self.0.progress = pb;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> ImgOptimizer {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImgOptimizer {
|
||||||
|
pub fn builder(dest_dir: &str, nb_workers: usize) -> ImgOptimizerBuilder {
|
||||||
|
ImgOptimizerBuilder::new(dest_dir, nb_workers)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn stop(&self) {
|
pub async fn stop(&self) {
|
||||||
@ -151,10 +183,7 @@ impl ImgOptimizer {
|
|||||||
self.cancel_token.cancel();
|
self.cancel_token.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn optimize(
|
pub async fn optimize(&self, file_group: &FileGroup) -> OptimizerResult {
|
||||||
&self,
|
|
||||||
file_group: &FileGroup,
|
|
||||||
) -> Result<OptimizerResult, Box<dyn std::error::Error>> {
|
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
let results = Arc::new(RwLock::new(FileGroup::new()));
|
let results = Arc::new(RwLock::new(FileGroup::new()));
|
||||||
@ -164,19 +193,13 @@ impl ImgOptimizer {
|
|||||||
self.queue.enqueue(file).await;
|
self.queue.enqueue(file).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pb = Arc::new(ProgressBar::new(file_group.len() as u64));
|
self.progress.set_message("optimizing...");
|
||||||
pb.set_style(
|
|
||||||
ProgressStyle::default_bar()
|
|
||||||
.template("{msg} [{bar:40}] {pos}/{len} ({eta})")?
|
|
||||||
.progress_chars("##-"),
|
|
||||||
);
|
|
||||||
pb.set_message("optimizing...");
|
|
||||||
|
|
||||||
for _ in 0..self.nb_workers {
|
for _ in 0..self.nb_workers {
|
||||||
let queue = Arc::clone(&self.queue);
|
let queue = Arc::clone(&self.queue);
|
||||||
let results = Arc::clone(&results);
|
let results = Arc::clone(&results);
|
||||||
let optimized = Arc::clone(&optimized);
|
let optimized = Arc::clone(&optimized);
|
||||||
let pb = Arc::clone(&pb);
|
let pb = Arc::clone(&self.progress);
|
||||||
|
|
||||||
let cancel_token = self.cancel_token.clone();
|
let cancel_token = self.cancel_token.clone();
|
||||||
let dest_dir = self.dest_dir.clone();
|
let dest_dir = self.dest_dir.clone();
|
||||||
@ -211,9 +234,8 @@ impl ImgOptimizer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(rmanach): move it on main not here
|
// TODO(rmanach): move it on main not here (overwrite progress bar message)
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
let pb = Arc::clone(&pb);
|
|
||||||
let optimizer = self.clone();
|
let optimizer = self.clone();
|
||||||
async move {
|
async move {
|
||||||
if let Err(e) = tokio::signal::ctrl_c().await {
|
if let Err(e) = tokio::signal::ctrl_c().await {
|
||||||
@ -222,23 +244,26 @@ impl ImgOptimizer {
|
|||||||
|
|
||||||
log::warn!("interrupt signal received");
|
log::warn!("interrupt signal received");
|
||||||
optimizer.stop().await;
|
optimizer.stop().await;
|
||||||
pb.finish_with_message("optimization interrupted");
|
optimizer
|
||||||
|
.progress
|
||||||
|
.finish_with_message("optimization interrupted");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.tracker.close();
|
self.tracker.close();
|
||||||
self.tracker.wait().await;
|
self.tracker.wait().await;
|
||||||
|
|
||||||
pb.finish_with_message("optimization complete");
|
self.progress.finish_with_message("optimization complete");
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"optimization finished in {:.2}s",
|
"optimization finished in {:.2}s",
|
||||||
start.elapsed().as_secs_f64()
|
start.elapsed().as_secs_f64()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(OptimizerResult {
|
OptimizerResult {
|
||||||
orig: file_group.clone(),
|
orig: file_group.clone(),
|
||||||
opti: results.read().await.clone(),
|
opti: results.read().await.clone(),
|
||||||
optimized: optimized.load(Ordering::Relaxed),
|
optimized: optimized.load(Ordering::Relaxed),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user