blob: 7e0f84b428486fee14b6f19e1e3efccacaf9f626 [file]
//! `amem tool` and `amem source`: a tool tap called as the owner, and the sources
//! tools brought in, listed, shown and swept.
use crate::Fallible;
use clap::Subcommand;
use dm_server::Memory;
use std::path::Path;
use std::sync::Arc;
/// What `amem source` does.
#[derive(Subcommand, Debug)]
pub enum SourceOp {
/// What tools brought in and the record keeps, newest first: the tool, what it was
/// asked, when it runs out, and whether it is held for the owner.
List,
/// One source in full, held or not: the owner's view.
Show {
/// Its id, as a citation names it: `source:<id>`.
id: String,
},
/// Drop the sources whose clock ran out and that no live entry cites.
Sweep,
/// Release a held answer once you have read it (`amem source show`): the same call
/// is served from it from then on, with what the scan found.
Release {
/// Its id: `source:<id>` or `<id>`.
id: String,
},
}
/// Call a tool as the owner: `args` is the tool's JSON.
///
/// # Errors
///
/// Arguments that are not JSON, or the tool's refusal or failure.
pub async fn call(root: &Path, tool: &str, args: &str) -> Fallible {
let args: serde_json::Value =
serde_json::from_str(args).map_err(|e| format!("args are not JSON: {e}"))?;
let m = Arc::new(Memory::open(root)?);
m.set_tools(crate::taps::TapTools::for_root(root));
let answer = m.use_tool(tool, args).await?;
println!("{}", serde_json::to_string_pretty(&answer)?);
Ok(())
}
/// `amem source`.
///
/// # Errors
///
/// Anyone but the owner, an unknown id, or a store error.
pub async fn cmd(m: &Memory, op: SourceOp) -> Fallible {
match op {
SourceOp::List => {
let rows: Vec<serde_json::Value> = m
.sources()
.await?
.iter()
.map(|s| {
serde_json::json!({
"id": s.id, "tool": s.tool, "args": s.args, "domain": s.domain,
"classification": s.classification.to_string(),
"kept_at": s.kept_at.to_string(), "retain_until": s.retain_until.to_string(),
"held": s.held, "findings": s.findings, "session": s.session,
})
})
.collect();
println!("{}", serde_json::to_string_pretty(&rows)?);
}
SourceOp::Show { id } => {
let id = id.strip_prefix(dm_server::sources::CITATION).unwrap_or(&id);
println!(
"{}",
serde_json::to_string_pretty(&m.source_for_owner(id).await?)?
);
}
SourceOp::Release { id } => {
let id = id.strip_prefix(dm_server::sources::CITATION).unwrap_or(&id);
let s = m.release_source(id).await?;
eprintln!(
"amem: {} released; it carries {}",
s.id,
if s.findings.is_empty() {
"nothing the scan found".to_string()
} else {
s.findings.join(", ")
}
);
println!("{}", serde_json::to_string_pretty(&s)?);
}
SourceOp::Sweep => {
let dropped = m.sweep_sources(time::OffsetDateTime::now_utc()).await?;
println!("{}", serde_json::to_string_pretty(&dropped)?);
}
}
Ok(())
}