use crate::*;
use alux_ext::ext;
use rsynko_session::Wanted;
use std::path::PathBuf;
use std::time::Duration;
const SUMMARY_COLUMNS: usize = 160;
const DETAIL_COLUMNS: usize = 500;
#[ext(name = ManagerAttentionExt)]
pub impl<This> This
where
This: QueueCatalogAlg + SafeExitAlg + TransferStateAlg + RehearsalStateAlg,
This::Entry: QueueEntryAlg,
This::Change: PlannedChangeAlg,
This::Id: Copy + Eq,
{
fn wanting_work(&self) -> Vec<This::Id> {
self.queue_ids().filter(|id| self.entry_phase(*id) == Some(TransferPhase::Waiting)).collect()
}
fn wanted(&self, id: This::Id) -> Wanted {
if self.exit_requested() {
return Wanted::Unwanted;
}
match self.entry_phase(id) {
None => Wanted::Unwanted,
Some(TransferPhase::Paused) => Wanted::Held,
Some(_) => Wanted::Running,
}
}
fn rehearses(&self, id: This::Id) -> bool {
self.queue_entry(id).and_then(QueueEntryAlg::dry_run) == Some(true)
}
fn begun(&mut self, id: This::Id, holdable: bool) {
if self.rehearses(id) {
self.apply_rehearsal_event(id, RehearsalObservationOp::Started {});
return;
}
self.apply_transfer_event(id, TransferObservationOp::Started {});
self.apply_transfer_event(id, TransferObservationOp::PauseCapability { supported: holdable });
}
fn ran_for(&mut self, id: This::Id, elapsed: Duration) {
if !self.rehearses(id) {
self.apply_transfer_event(id, TransferObservationOp::Elapsed { elapsed });
}
}
fn refused(&mut self, id: This::Id, detail: &str) {
if self.rehearses(id) {
self.apply_rehearsal_event(id, RehearsalObservationOp::Failed { message: summary_line(detail) });
return;
}
self.apply_transfer_event(
id,
TransferObservationOp::ProgramFailed { summary: summary_line(detail), detail: detail_text(detail) },
);
}
fn performed(&mut self, id: This::Id, destination: PathBuf, changes: Vec<This::Change>) {
if self.rehearses(id) {
self.apply_rehearsal_event(id, RehearsalObservationOp::Reported { changes });
return;
}
let bytes = changes.iter().filter_map(PlannedChangeAlg::change_size).fold(0_u64, u64::saturating_add);
self.apply_transfer_event(id, TransferObservationOp::Completed { destination, bytes });
}
fn destination_is_taken(&self, id: This::Id) -> bool {
let Some(destination) = self.queue_entry(id).and_then(QueueEntryAlg::output) else {
return false;
};
self.queue_ids()
.filter(|other| *other != id)
.filter(|other| self.entry_phase(*other).is_some_and(TransferPhase::is_running))
.any(|other| self.queue_entry(other).and_then(QueueEntryAlg::output) == Some(destination))
}
fn entry_phase(&self, id: This::Id) -> Option<TransferPhase> {
self.queue_entry(id).map(QueueEntryAlg::phase)
}
}
pub fn summary_line(detail: &str) -> String {
detail.lines().next().unwrap_or_default().chars().take(SUMMARY_COLUMNS).collect()
}
pub fn detail_text(detail: &str) -> String {
detail.chars().take(DETAIL_COLUMNS).collect()
}