loading bar when downloading
This commit is contained in:
parent
80d497d47c
commit
dfd42389f3
@ -9,7 +9,6 @@ use crate::utils::api::ApiProps;
|
|||||||
use crate::global::global::{DIR_PATH, set_dir_path};
|
use crate::global::global::{DIR_PATH, set_dir_path};
|
||||||
use crate::services::api::ApiError;
|
use crate::services::api::ApiError;
|
||||||
use crate::services::req_props::{ReqProps, ObjProps};
|
use crate::services::req_props::{ReqProps, ObjProps};
|
||||||
use crate::services::download_files::DownloadFiles;
|
|
||||||
use crate::store::object::{tree, blob};
|
use crate::store::object::{tree, blob};
|
||||||
use crate::commands::config;
|
use crate::commands::config;
|
||||||
use crate::commands::init;
|
use crate::commands::init;
|
||||||
@ -127,6 +126,7 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
let downloader = Downloader::new()
|
let downloader = Downloader::new()
|
||||||
.set_api_props(api_props.clone())
|
.set_api_props(api_props.clone())
|
||||||
.set_files(files)
|
.set_files(files)
|
||||||
|
.should_log()
|
||||||
.download(ref_path.clone(), Some(&save_blob));
|
.download(ref_path.clone(), Some(&save_blob));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 abs_p = ref_p.join(PathBuf::from(self.relative_ps.clone()));
|
||||||
let mut file = File::create(abs_p).unwrap();
|
let mut file = File::create(abs_p).unwrap();
|
||||||
|
|
||||||
@ -48,11 +48,18 @@ impl DownloadFiles {
|
|||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
let res = self.send().await.map_err(ApiError::RequestError)?;
|
||||||
if res.status().is_success() {
|
if res.status().is_success() {
|
||||||
let mut stream = res.bytes_stream();
|
let mut stream = res.bytes_stream();
|
||||||
|
|
||||||
while let Some(chunk) = stream.next().await {
|
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()));
|
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(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ApiError::IncorrectRequest(res))
|
Err(ApiError::IncorrectRequest(res))
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use indicatif::{ProgressBar, MultiProgress, ProgressStyle, HumanBytes};
|
||||||
|
|
||||||
use crate::utils::api::ApiProps;
|
use crate::utils::api::ApiProps;
|
||||||
use crate::services::api::ApiError;
|
use crate::services::api::ApiError;
|
||||||
use crate::services::download_files::DownloadFiles;
|
use crate::services::download_files::DownloadFiles;
|
||||||
@ -10,6 +12,8 @@ pub struct Downloader {
|
|||||||
files: Vec<ObjProps>,
|
files: Vec<ObjProps>,
|
||||||
should_log: bool,
|
should_log: bool,
|
||||||
api_props: Option<ApiProps>,
|
api_props: Option<ApiProps>,
|
||||||
|
progress_bars: Vec<ProgressBar>,
|
||||||
|
multi_progress: Option<MultiProgress>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Downloader {
|
impl Downloader {
|
||||||
@ -18,6 +22,8 @@ impl Downloader {
|
|||||||
files: vec![],
|
files: vec![],
|
||||||
should_log: false,
|
should_log: false,
|
||||||
api_props: None,
|
api_props: None,
|
||||||
|
progress_bars: vec![],
|
||||||
|
multi_progress: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,35 +47,95 @@ impl Downloader {
|
|||||||
self
|
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)>) {
|
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() {
|
for file in self.files.clone() {
|
||||||
let relative_s = &file.clone().relative_s.unwrap();
|
let relative_s = &file.clone().relative_s.unwrap();
|
||||||
let mut download = DownloadFiles::new();
|
let mut download = DownloadFiles::new();
|
||||||
download.set_url(&relative_s, &self.api_props.clone().unwrap());
|
download.set_url(&relative_s, &self.api_props.clone().unwrap());
|
||||||
|
|
||||||
let res = {
|
let should_use_stream = {
|
||||||
if let Some(size) = file.contentlength {
|
if let Some(size) = file.contentlength {
|
||||||
if size > SIZE_TO_STREAM {
|
if size > SIZE_TO_STREAM {
|
||||||
download.save_stream(ref_p.clone())
|
true
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
download.save(ref_p.clone())
|
download.save(ref_p.clone())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// deal with error
|
||||||
match res {
|
match res {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
if let Some(fct) = callback {
|
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(_)) => {
|
Err(ApiError::Unexpected(_)) => {
|
||||||
eprintln!("err: writing {}", relative_s);
|
eprintln!("err: writing {}", relative_s);
|
||||||
@ -84,6 +150,22 @@ impl Downloader {
|
|||||||
std::process::exit(1);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user