use std::time::Duration;
use serde_json::Value;
use super::client::Seat;
use crate::boundary::codec;
use crate::boundary::reply::{self, Reply};
use crate::boundary::{Action, Gesture, Query};
use crate::registry::mailbox::{Capture, Completion, Invocation, Verb};
use crate::xdg::Env;
pub mod config;
pub mod exec;
const VERB: &str = super::HOST_SUBCMD;
const DEADLINE: Duration = Duration::from_mins(2);
pub fn run(world: &Env, args: &[String]) -> i32 {
if let Some(extra) = args.first() {
eprintln!("yog {VERB}: takes no arguments, got {extra:?}");
return super::seat::USAGE_EXIT;
}
eprintln!("yog {VERB}: {}", serve(world));
1
}
fn serve(world: &Env) -> String {
let set = match config::read(&config::path(world)) {
Ok(set) => set,
Err(reason) => return reason,
};
let seat = match super::seat::open(world) {
Ok(seat) => seat,
Err(reason) => return reason,
};
let presenting = Gesture::Act(Action::Advertise {
tools: config::advertisement(&set),
});
if let Err(reason) = tell(&seat, &presenting) {
return reason;
}
loop {
let work = match waited(&seat) {
Ok(work) => work,
Err(reason) => return reason,
};
for invocation in work {
let capture = exec::execute(&set, &invocation, DEADLINE);
if let Err(reason) = answer(&seat, &invocation, capture) {
return reason;
}
}
}
}
fn waited(seat: &Seat) -> Result<Vec<Invocation>, String> {
match tell(seat, &Gesture::Ask(Query::Invocations))? {
Reply::Invocations(rows) => Ok(rows),
other => Err(format!(
"engine answered {other:?}, not this machine's work"
)),
}
}
fn answer(seat: &Seat, invocation: &Invocation, capture: Capture) -> Result<(), String> {
tell(
seat,
&Gesture::Act(Action::Route(Verb::Complete(Completion {
invocation: invocation.id.clone(),
capture,
}))),
)
.map(|_| ())
}
fn tell(seat: &Seat, gesture: &Gesture) -> Result<Reply, String> {
let stream = seat.ask(&codec::encode(gesture))?;
let last: &Value = stream
.last()
.ok_or("the engine closed the stream without answering")?;
match reply::decode(last) {
Ok(answered) => answered,
Err(e) => Err(format!("undecodable engine reply: {e}")),
}
}
#[cfg(test)]
mod tests;