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()
}