loading bar when downloading

This commit is contained in:
grimhilt 2023-07-14 15:33:44 +02:00
parent 80d497d47c
commit dfd42389f3
3 changed files with 102 additions and 13 deletions

View File

@ -9,7 +9,6 @@ use crate::utils::api::ApiProps;
use crate::global::global::{DIR_PATH, set_dir_path};
use crate::services::api::ApiError;
use crate::services::req_props::{ReqProps, ObjProps};
use crate::services::download_files::DownloadFiles;
use crate::store::object::{tree, blob};
use crate::commands::config;
use crate::commands::init;
@ -127,6 +126,7 @@ pub fn clone(remote: Values<'_>) {
let downloader = Downloader::new()
.set_api_props(api_props.clone())
.set_files(files)
.should_log()
.download(ref_path.clone(), Some(&save_blob));
}

View File

@ -40,7 +40,7 @@ impl DownloadFiles {
}
}
pub fn save_stream(&mut self, ref_p: PathBuf) -> Result<(), ApiError> {
pub fn save_stream(&mut self, ref_p: PathBuf, callback: Option<impl Fn(u64)>) -> Result<(), ApiError> {
let abs_p = ref_p.join(PathBuf::from(self.relative_ps.clone()));
let mut file = File::create(abs_p).unwrap();
@ -48,11 +48,18 @@ impl DownloadFiles {
let res = self.send().await.map_err(ApiError::RequestError)?;
if res.status().is_success() {
let mut stream = res.bytes_stream();
while let Some(chunk) = stream.next().await {
if let Err(err) = file.write_all(&chunk.unwrap()) {
let unwrap_chunk = chunk.unwrap();
// save chunk inside file
if let Err(err) = file.write_all(&unwrap_chunk) {
return Err(ApiError::Unexpected(err.to_string()));
} else if let Some(fct) = &callback {
// call callback with size of this chunk
fct(unwrap_chunk.len().try_into().unwrap());
}
}
Ok(())
} else {
Err(ApiError::IncorrectRequest(res))

View File

@ -1,4 +1,6 @@
use std::path::PathBuf;
use indicatif::{ProgressBar, MultiProgress, ProgressStyle, HumanBytes};
use crate::utils::api::ApiProps;
use crate::services::api::ApiError;
use crate::services::download_files::DownloadFiles;
@ -10,6 +12,8 @@ pub struct Downloader {
files: Vec<ObjProps>,
should_log: bool,
api_props: Option<ApiProps>,
progress_bars: Vec<ProgressBar>,
multi_progress: Option<MultiProgress>,
}
impl Downloader {
@ -18,6 +22,8 @@ impl Downloader {
files: vec![],
should_log: false,
api_props: None,
progress_bars: vec![],
multi_progress: None,
}
}
@ -41,35 +47,95 @@ impl Downloader {
self
}
fn init_log(&mut self, nb_objs: u64, total_size: u64) {
self.multi_progress = Some(MultiProgress::new());
self.progress_bars.push(
self.multi_progress
.clone()
.unwrap()
.add(ProgressBar::new(nb_objs).with_message("Objects")));
let msg = format!("0B/{}", HumanBytes(total_size).to_string());
self.progress_bars.push(
self.multi_progress
.clone()
.unwrap()
.add(ProgressBar::new(total_size).with_message(msg)));
self.progress_bars[0].set_style(
ProgressStyle::with_template("{_:>10} [{bar:40}] {pos}/{len} {msg}")
.unwrap()
.progress_chars("=> "));
self.progress_bars[1].set_style(
ProgressStyle::with_template("[{elapsed_precise}] [{bar:40}] {msg}")
.unwrap()
.progress_chars("=> "));
self.progress_bars[0].tick();
self.progress_bars[1].tick();
}
fn update_bytes_bar(&self, size: u64) {
let bytes_bar = &self.progress_bars[1];
bytes_bar.inc(size);
let msg = format!(
"{}/{}",
HumanBytes(bytes_bar.position()).to_string(),
HumanBytes(bytes_bar.length().unwrap()).to_string());
bytes_bar.set_message(msg);
}
pub fn download(&mut self, ref_p: PathBuf, callback: Option<&dyn Fn(ObjProps)>) {
if self.should_log {
let mut total_size = 0;
let nb_objs = self.files.len();
self.files
.iter()
.for_each(|f|
if let Some(size) = f.contentlength {
total_size += size
}
);
self.init_log(nb_objs.try_into().unwrap(), total_size);
}
for file in self.files.clone() {
let relative_s = &file.clone().relative_s.unwrap();
let mut download = DownloadFiles::new();
download.set_url(&relative_s, &self.api_props.clone().unwrap());
let res = {
let should_use_stream = {
if let Some(size) = file.contentlength {
if size > SIZE_TO_STREAM {
download.save_stream(ref_p.clone())
true
} else {
download.save(ref_p.clone())
false
}
} else {
false
}
};
// download
let res = {
if should_use_stream {
// todo should increment here
download.save_stream(ref_p.clone(), Some(|a| self.update_bytes_bar(a)))
} else {
download.save(ref_p.clone())
}
};
// deal with error
match res {
Ok(()) => {
if let Some(fct) = callback {
fct(file);
fct(file.clone());
}
//let relative_p = PathBuf::from(&relative_s);
//let lastmodified = obj.clone().lastmodified.unwrap().timestamp_millis();
//if let Err(err) = blob::add(relative_p, &lastmodified.to_string()) {
// eprintln!("err: saving ref of {} ({})", relative_s.clone(), err);
//}
},
Err(ApiError::Unexpected(_)) => {
eprintln!("err: writing {}", relative_s);
@ -84,6 +150,22 @@ impl Downloader {
std::process::exit(1);
}
}
// increment loading bars
if self.should_log {
self.progress_bars[0].inc(1); // increment object
// increment bytes only if
// not incremented continuously by stream
if !should_use_stream {
self.update_bytes_bar(file.contentlength.unwrap());
}
}
}
// finish all bars
for bar in &self.progress_bars {
bar.finish();
}
}
}