Merge pull request 'feat(sidecar): protocol 14 — the console command run forward (PLAN_REDESIGNS §16)' (#30) from feat/command-steps into edge
Reviewed-on: #30
This commit is contained in:
@@ -208,6 +208,11 @@ use tracing_subscriber::EnvFilter;
|
||||
/// retry never places a second; the crate is kept when the run ends (D373). `gc.started`,
|
||||
/// `gc.ended` and `gc.failed` ride the feed like any other event.
|
||||
///
|
||||
/// Console commands as event steps (§20.11, the module's PLAN_REDESIGNS.md §16) add one forward,
|
||||
/// `POST /commands/run`: the commands a step's author typed, run once or once per online
|
||||
/// recipient. The plugin remembers the key so nothing runs twice; this process keeps nothing and
|
||||
/// knows nothing of what a command does.
|
||||
///
|
||||
/// `docs/rust-link/PROTOCOL.md` is the specification — §8 the read path, §9 identity, §10 the
|
||||
/// mirror, §11 configuration, §12 clans, §13 the raid frame, §14 the leases, §15 the world verbs,
|
||||
/// §16 the rewards, §17 the map, §18 the optional mods, §19 the walk's fixes, §20 the step editor;
|
||||
|
||||
@@ -131,6 +131,10 @@ pub async fn serve(addr: &str, state: AppState) -> anyhow::Result<()> {
|
||||
// Protocol 14 (§20.9): place one guarded crate. The plugin remembers the key; the crate is
|
||||
// kept when the run ends (Guarded Crate cannot end one alone), so nothing is kept here.
|
||||
.route("/gc/place", post(gc_place))
|
||||
// Protocol 14 (§20.11): console commands a step's author typed. The plugin keeps the key
|
||||
// so nothing runs twice, fills the placeholders and decides who is online; this process
|
||||
// moves the line and knows nothing of what any command does (no allowlist, D384).
|
||||
.route("/commands/run", post(commands_run))
|
||||
// Protocol 10 (§29): who took part, what they may redeem, and a line in chat. The tally
|
||||
// is counted and held by the plugin, the kit catalogue is Kits' own, and whether a chat
|
||||
// line was already said is the plugin's memory. These move lines, like everything above.
|
||||
@@ -583,6 +587,16 @@ async fn gc_place(State(st): State<AppState>, Json(body): Json<Value>) -> Respon
|
||||
forward_object(&st, body, "gc.place", "a guarded crate placement").await
|
||||
}
|
||||
|
||||
/// Run the console commands a step's author typed (protocol 14): once, or once per online
|
||||
/// recipient. `command.ran` (how many ran, the console's replies, who was skipped as offline, and
|
||||
/// `repeat` for a key already seen) or `command.error` with a reason, `unknown-command` among
|
||||
/// them. A step's `teardown` rides its run and the plugin keeps it with the key; `teardownOf`
|
||||
/// asks for the teardown kept under another key (D385). The plugin remembers the key, so nothing
|
||||
/// is remembered here.
|
||||
async fn commands_run(State(st): State<AppState>, Json(body): Json<Value>) -> Response {
|
||||
forward_object(&st, body, "command.run", "a console command run").await
|
||||
}
|
||||
|
||||
/// Start counting who takes part in a run. `tally.ok` or `tally.error` with a reason.
|
||||
async fn tally_open(State(st): State<AppState>, Json(body): Json<Value>) -> Response {
|
||||
forward_object(&st, body, "tally.open", "a tally").await
|
||||
@@ -1346,6 +1360,43 @@ mod tests {
|
||||
assert!(stamp(json!("Elite"), "gc.place", "r-63").is_none());
|
||||
}
|
||||
|
||||
/// Protocol 14, console commands: a run is stamped `command.run` whatever its body names, so
|
||||
/// the route runs commands and nothing else, and its key, commands and recipients pass through
|
||||
/// byte for byte; the placeholders are the plugin's to fill.
|
||||
#[test]
|
||||
fn protocol_14_command_run_is_stamped() {
|
||||
let body = json!({ "cmd": "gc.place", "reqId": "theirs", "key": "12:5",
|
||||
"commands": ["sr add {steamid} 100", "say \"{name} won\""],
|
||||
"recipients": [{ "steamId": "76561198000000001", "name": "Some \"One\"" }] });
|
||||
let stamped = stamp(body, "command.run", "r-64").expect("an object is stamped");
|
||||
|
||||
assert_eq!(stamped["cmd"], "command.run");
|
||||
assert_eq!(stamped["reqId"], "r-64");
|
||||
assert_eq!(stamped["key"], "12:5");
|
||||
assert_eq!(stamped["commands"][0], "sr add {steamid} 100");
|
||||
assert_eq!(stamped["commands"][1], "say \"{name} won\"");
|
||||
assert_eq!(stamped["recipients"][0]["name"], "Some \"One\"");
|
||||
assert!(stamp(json!(["rbe"]), "command.run", "r-65").is_none());
|
||||
|
||||
// D385: a step's teardown rides its run, and a teardown asked for by key alone names the
|
||||
// run it is for; both are the plugin's to read.
|
||||
let run = stamp(
|
||||
json!({ "key": "12:6", "commands": ["rbe 1"], "teardown": ["rbe stop"] }),
|
||||
"command.run",
|
||||
"r-66",
|
||||
)
|
||||
.expect("an object is stamped");
|
||||
assert_eq!(run["teardown"][0], "rbe stop");
|
||||
let teardown = stamp(
|
||||
json!({ "key": "12:6:teardown", "teardownOf": "12:6" }),
|
||||
"command.run",
|
||||
"r-67",
|
||||
)
|
||||
.expect("an object is stamped");
|
||||
assert_eq!(teardown["cmd"], "command.run");
|
||||
assert_eq!(teardown["teardownOf"], "12:6");
|
||||
}
|
||||
|
||||
/// Protocol 12: a title set is forwarded whole. The markup inside each `text` is the module's
|
||||
/// and the plugin's business, so it must arrive byte for byte as the website composed it.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user