use crate::{autoheal, config, watch};
use anyhow::{anyhow, Result};
use std::path::PathBuf;
fn resolve_clone(role: &Option<String>) -> Result<PathBuf> {
if let Ok(root) = config::repo_root() {
return Ok(root);
}
let reg = autoheal::load();
let me_session = autoheal::current_session();
let mut owned: Vec<&autoheal::Target> = reg
.targets
.iter()
.filter(|t| autoheal::owned_by_session(t, &me_session, role))
.filter(|t| role.as_ref().is_none_or(|r| &t.role == r))
.collect();
owned.sort_by(|a, b| a.hub.cmp(&b.hub).then(a.role.cmp(&b.role)));
owned.dedup_by(|a, b| a.hub == b.hub && a.role == b.role);
match owned.as_slice() {
[] => Err(anyhow!(
"confer arm: not inside a confer clone, and no watch target owned by this session.\n\
cd into your role's clone and re-run (see `confer clones`), pass `--role <r>`, or \
`confer reconnect`."
)),
[t] => Ok(PathBuf::from(&t.hub)),
many => {
let list = many
.iter()
.map(|t| format!(" • {} @ {}", t.role, t.hub))
.collect::<Vec<_>>()
.join("\n");
Err(anyhow!(
"confer arm: several watch targets are owned here — cd into the one you mean, or \
pass `--role <r>`:\n{list}"
))
}
}
}
pub fn run(
role: Option<String>,
topic: Option<String>,
all: bool,
min_priority: Option<String>,
wake_on: Option<String>,
) -> Result<()> {
let clone = resolve_clone(&role)?;
std::env::set_current_dir(&clone)
.map_err(|e| anyhow!("confer arm: cannot enter clone {}: {e}", clone.display()))?;
let hub_key = config::hub_key(&clone);
let resolved_role = config::resolve_role(role.clone(), &clone).unwrap_or_default();
let (wake_on, min_priority, topic, all) = watch::resolve_watch_prefs(
&hub_key,
&resolved_role,
wake_on.as_deref(),
min_priority.as_deref(),
topic.as_deref(),
all,
)?;
watch::run(watch::WatchOpts {
topic,
role,
json: false,
poll_secs: 10,
advance: true,
replace: true,
all,
min_priority,
wake_on,
no_version_notice: false,
delivery: Some("monitor".to_string()),
})
}