use std::path::Path;
use trusty_mpm::client::DaemonClient;
use trusty_mpm::client::http_client::supervisor::RegisterCallError;
use trusty_mpm::core::architect_sidecar_prune::{self as prune, SidecarProbes};
use trusty_mpm::session_manager::supervisor_register::collector_session_name;
use trusty_mpm::session_manager::{RegistrationReport, SessionKind, SupervisorRegistration};
use super::launch::PaneState;
use super::session_name::SessionNames;
use super::{Probe, Step};
pub(crate) fn registration(dir: &Path, names: &SessionNames) -> SupervisorRegistration {
SupervisorRegistration {
dir: dir.to_path_buf(),
session: names.architect().to_owned(),
poll_session: Some(names.poll().to_owned()),
collector_session: Some(collector_session_name(names.architect())),
}
}
pub(crate) async fn register(reg: &SupervisorRegistration) -> Step {
let outcome = match DaemonClient::from_resolved_socket() {
Ok(client) => client.register_supervisor(reg).await,
Err(e) => Err(RegisterCallError::Unreachable(format!("{e:#}"))),
};
register_step(reg, outcome)
}
pub(crate) fn register_step(
reg: &SupervisorRegistration,
outcome: Result<RegistrationReport, RegisterCallError>,
) -> Step {
match outcome {
Ok(report) => match report.registered.first() {
Some(first)
if first.kind == SessionKind::Supervisor && first.tmux_name == reg.session =>
{
let helpers: Vec<&str> = report.registered[1..]
.iter()
.map(|r| r.tmux_name.as_str())
.collect();
Step::Changed(format!(
"registered {} with the daemon as the Architect (record {}; helpers: {})",
reg.session,
first.id,
if helpers.is_empty() {
"none".to_owned()
} else {
helpers.join(", ")
}
))
}
_ => Step::Failed(format!(
"registration: the daemon's answer does not name the Architect's record for {}: \
{report:?}",
reg.session
)),
},
Err(RegisterCallError::Unreachable(why)) => {
let text = format!(
"NOT registered with the daemon ({why}); `tm ls` will not list the Architect \
until `tm fleet init` runs again with the daemon up"
);
eprintln!("warning: {text}");
Step::Skipped(text)
}
Err(e) => Step::Failed(format!("registration of {}: {e}", reg.session)),
}
}
pub(crate) fn prune_step(home: &Path, probe: Probe) -> Option<Step> {
let session_exists = |name: &str| match (probe.pane)(name) {
PaneState::Absent => Some(false),
PaneState::Live(_) | PaneState::Dead(_) => Some(true),
PaneState::Unknown(_) => None,
};
let probes = SidecarProbes {
pid_alive: &prune::pid_alive,
start_time: &prune::start_time,
session_exists: &session_exists,
};
let root = home.join(".trusty-mpm");
match prune::prune_stale_sidecars(&root, probes) {
Err(why) => Some(Step::Unchanged(format!(
"Architect sidecars kept: cannot list them ({why})"
))),
Ok(report) if !report.pruned.is_empty() => Some(Step::Changed(format!(
"pruned the stale Architect sidecar(s) of {}{}",
report.pruned.join(", "),
kept_note(&report.kept)
))),
Ok(report) if !report.kept.is_empty() => Some(Step::Unchanged(format!(
"Architect sidecars kept{}",
kept_note(&report.kept)
))),
Ok(_) => None,
}
}
fn kept_note(kept: &[String]) -> String {
if kept.is_empty() {
String::new()
} else {
format!("; kept, not proven stale: {}", kept.join("; "))
}
}
#[cfg(test)]
#[path = "register_tests.rs"]
mod tests;