use crate::actions::verbs::log_step_failure;
use crate::opslog::Origin;
use crate::ui_state::UiState;
use serde_json::Value;
use std::fs;
use std::path::Path;
use super::dispatch::{Deps, dispatch};
use super::{Gesture, answer, codec, deposit, reply};
pub fn consume(deps: &Deps, ui: &mut UiState, ts: &str, now_unix: i64) -> usize {
let root = deps.state_root.clone();
let mut consumed = 0;
for (id, _) in deposit::pending(&root) {
let Ok(claim) = deposit::claim(&root, &id) else {
continue;
};
let answered = run(
deps,
ui,
ts,
now_unix,
&fs::read(claim.path()).unwrap_or_default(),
);
if deposit::write_reply(&root, &id, &answered).is_err() {
let _ = log_step_failure(
&root,
ts,
&deposit::gestures_dir(&root),
"gesture-reply",
&format!("reply for {id:?} could not be written"),
Origin::World,
);
}
consumed += 1;
}
consumed
}
pub fn sweep(state_root: &Path, ts: &str) -> usize {
let mut answered = 0;
for (id, path) in deposit::claimed(state_root) {
if deposit::read_reply(state_root, &id).is_some() || !deposit::unheld(&path) {
continue;
}
let refusal = reply::refusal(&format!(
"gesture {id:?} was claimed and its engine died before replying; \
the effect is in doubt — read the world (the ops trail, the \
transcript, the roster) before acting again: a re-send is a \
second act, not a retry"
));
if deposit::write_reply(state_root, &id, &refusal).is_err() {
let _ = log_step_failure(
state_root,
ts,
&deposit::gestures_dir(state_root),
"gesture-reply",
&format!("reply for {id:?} could not be written"),
Origin::World,
);
continue;
}
let _ = log_step_failure(
state_root,
ts,
&deposit::gestures_dir(state_root),
"gesture-debris",
&format!("gesture {id:?} died in flight; answered in doubt"),
Origin::World,
);
answered += 1;
}
answered
}
fn run(deps: &Deps, ui: &mut UiState, ts: &str, now_unix: i64, bytes: &[u8]) -> Value {
let parsed: Value = match serde_json::from_slice(bytes) {
Ok(v) => v,
Err(e) => return reply::refusal(&format!("deposit is not JSON: {e}")),
};
run_value(deps, ui, ts, now_unix, &parsed)
}
pub(crate) fn run_value(
deps: &Deps,
ui: &mut UiState,
ts: &str,
now_unix: i64,
parsed: &Value,
) -> Value {
match codec::decode(parsed) {
Ok(gesture) => run_gesture(deps, ui, ts, now_unix, &gesture),
Err(e) => reply::refusal(&e),
}
}
pub(crate) fn run_gesture(
deps: &Deps,
ui: &mut UiState,
ts: &str,
now_unix: i64,
gesture: &Gesture,
) -> Value {
match gesture {
Gesture::Act(action) => match dispatch(deps, ui, ts, action) {
Ok(r) => reply::encode(&r),
Err(e) => reply::refusal(&e),
},
Gesture::Ask(query) => match answer::answer(query, deps, ui, now_unix) {
Ok(r) => reply::encode(&r),
Err(e) => reply::refusal(&e),
},
}
}
#[cfg(test)]
mod tests;