use serde_json::Value;
use std::path::Path;
use super::{Gesture, Query, codec, deposit, help, line};
mod argv;
pub const TIMEOUT_EXIT: i32 = 124;
pub const USAGE_EXIT: i32 = 2;
pub fn run(
state_root: &Path,
args: &[String],
seed: &str,
waits: u32,
wait: &mut dyn FnMut(),
) -> i32 {
let (gesture, value) = match argv::read(args).and_then(|it| envelope(&it)) {
Ok(read) => read,
Err(e) => {
eprintln!("yog gesture: {e}");
return USAGE_EXIT;
}
};
if let Gesture::Ask(Query::Help { verb }) = &gesture {
println!("{}", help::render(&help::rows(verb.as_deref())));
return 0;
}
let (id, deposited) = match deposit::mint(state_root, seed)
.and_then(|id| deposit::deposit(state_root, &id, &value).map(|path| (id, path)))
{
Ok(minted) => minted,
Err(e) => {
eprintln!("yog gesture: deposit failed: {e}");
return 1;
}
};
for _ in 0..waits {
if let Some(reply) = deposit::read_reply(state_root, &id) {
println!("{reply}");
let ok = reply.get("ok").and_then(Value::as_bool).unwrap_or(false);
return i32::from(!ok);
}
wait();
}
eprintln!(
"yog gesture: no consumer answered; the deposit remains at {}",
deposited.display()
);
TIMEOUT_EXIT
}
fn envelope(invocation: &argv::Invocation) -> Result<(Gesture, Value), String> {
if line::is_command(&invocation.payload) {
let gesture = line::parse(&invocation.payload, &invocation.context)?;
let value = codec::encode(&gesture);
return Ok((gesture, value));
}
let value: Value =
serde_json::from_str(&invocation.payload).map_err(|e| format!("not JSON: {e}"))?;
Ok((codec::decode(&value)?, value))
}
#[cfg(test)]
mod tests;