use console::style;
use indicatif::{HumanBytes, ProgressBar, ProgressStyle};
use crate::action::{Action, BuildStepId, ResultFields, StartFields};
use crate::handlers::logs::LogHandler;
use crate::state::{Handler, HandlerResult, State};
use crate::style::{format_build_target, format_short_build_target, template_style};
const MIN_PROGRESS_PAYLOAD: u64 = 10 * 1024 * 1024;
fn get_style(size: u16) -> ProgressStyle {
template_style(
size,
true,
|size| match size {
0..=50 => "{prefix} {wide_msg}",
51..=60 => "{prefix} {wide_msg} {binary_bytes_per_sec:^12}",
_ => "{prefix} {wide_msg} {binary_bytes_per_sec:^12} {bytes:^12}",
},
|size| format!("[{{bar:{size}}}]"),
)
}
pub fn handle_new_download(state: &mut State, action: &Action) -> anyhow::Result<HandlerResult> {
if let Action::Start {
start_type: StartFields::CopyPath { path, .. },
id,
..
} = action
{
state.plug(LogHandler::new(*id));
state.plug(WaitForTransfer {
copy_id: *id,
path: path.to_string(),
})
};
Ok(HandlerResult::Continue)
}
struct WaitForTransfer {
copy_id: BuildStepId,
path: String,
}
impl Handler for WaitForTransfer {
fn on_action(&mut self, state: &mut State, action: &Action) -> anyhow::Result<HandlerResult> {
match action {
Action::Start {
start_type: StartFields::FileTransfer { .. },
id,
parent,
..
} if *parent == self.copy_id => {
state.plug(Transfer {
transfer_id: *id,
progress: None,
path: std::mem::take(&mut self.path),
});
state.plug(LogHandler::new(*id));
Ok(HandlerResult::Close)
}
_ => Ok(HandlerResult::Continue),
}
}
}
struct Transfer {
transfer_id: BuildStepId,
progress: Option<ProgressBar>,
path: String,
}
impl Handler for Transfer {
fn on_action(&mut self, state: &mut State, action: &Action) -> anyhow::Result<HandlerResult> {
match action {
Action::Result {
id,
fields: ResultFields::Progress { done, expected, .. },
} if *id == self.transfer_id => {
self.progress = self.progress.take().or_else(|| {
if *expected > 0 {
if *expected >= MIN_PROGRESS_PAYLOAD {
let pb = ProgressBar::new(*expected)
.with_style(get_style(state.term_size))
.with_prefix("Download")
.with_message(format_short_build_target(&self.path));
Some(state.add(pb))
} else {
Some(ProgressBar::hidden())
}
} else {
None
}
});
if let Some(progress) = &self.progress {
progress.set_length(*expected);
progress.set_position(*done);
}
Ok(HandlerResult::Continue)
}
Action::Stop { id } if *id == self.transfer_id => {
if state.cmd.args.log_downloads {
if let Some(progress) = &self.progress {
let msg_main = format!(
"{} Downloaded {}",
style("тнг").green(),
format_build_target(&self.path),
);
let msg_stats = style(format!(
" ({}, {:.0?})",
HumanBytes(progress.position()),
progress.duration(),
))
.dim()
.to_string();
state.println(msg_main + &msg_stats)?;
progress.finish_and_clear();
}
}
Ok(HandlerResult::Close)
}
_ => Ok(HandlerResult::Continue),
}
}
fn on_resize(&mut self, state: &mut State) -> anyhow::Result<()> {
if let Some(progress) = &self.progress {
progress.set_style(get_style(state.term_size));
}
Ok(())
}
}