Merge pull request 'feat(sidecar): POST /permissions/inventory forwards the plugin's store read' (#20) from feat/perm-inventory into edge
Reviewed-on: #20
This commit is contained in:
@@ -171,6 +171,10 @@ use tracing_subscriber::EnvFilter;
|
||||
/// whatever its kind — so what changes here is what no longer has to fit: the reload window that
|
||||
/// had to sit inside [`rpc::REPLY_TIMEOUT`] is gone.
|
||||
///
|
||||
/// The permission manager's redesign (the module's PLAN_REDESIGNS.md §1, D160) adds one route,
|
||||
/// `POST /permissions/inventory`: the plugin's whole store, in pages it sizes to the game link's
|
||||
/// line cap. Forwarded like every other object; the pages are never kept here.
|
||||
///
|
||||
/// `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; this constant is one
|
||||
|
||||
@@ -95,6 +95,10 @@ pub async fn serve(addr: &str, state: AppState) -> anyhow::Result<()> {
|
||||
// plugin will do with any of it. It puts `cmd` and `reqId` on the object and forwards it,
|
||||
// exactly as it forwards a link code.
|
||||
.route("/permissions/sync", post(perm_sync))
|
||||
// Protocol 13 (D160): the whole store, owners included, in pages. The body is
|
||||
// `{snapshotId?, page?}` and is forwarded as it is; paging is the plugin's and the
|
||||
// website's business, never this process's, which keeps no copy of any page.
|
||||
.route("/permissions/inventory", post(perm_inventory))
|
||||
// Protocol 5 (R18): the plugin's own view of the game host's configuration tree. All
|
||||
// three are correlated round trips and all three fail when the game is down, because
|
||||
// "what is on that host's disk" has no stale answer worth giving — and, unlike a board,
|
||||
@@ -435,6 +439,13 @@ async fn perm_sync(State(st): State<AppState>, Json(body): Json<Value>) -> Respo
|
||||
respond(st.rpc.call(&st.game, command, &req_id).await)
|
||||
}
|
||||
|
||||
/// One page of the plugin's permission inventory (protocol 13). Page 0 without a `snapshotId`
|
||||
/// starts a fresh read; any other page names the snapshot page 0 answered with. A `perm.error`
|
||||
/// (`busy`, `stale`, `too-large`) is an answer, and arrives as a `200` like the sync's.
|
||||
async fn perm_inventory(State(st): State<AppState>, Json(body): Json<Value>) -> Response {
|
||||
forward_object(&st, body, "perm.inventory", "an inventory request").await
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ConfigPathQuery {
|
||||
path: String,
|
||||
@@ -1081,6 +1092,20 @@ mod tests {
|
||||
assert!(stamp(json!(["9"]), "tally.close", "r-4").is_none());
|
||||
}
|
||||
|
||||
/// Protocol 13: an inventory page request keeps its paging fields and cannot become a sync.
|
||||
#[test]
|
||||
fn an_inventory_request_cannot_choose_its_own_command() {
|
||||
let body =
|
||||
json!({ "cmd": "perm.sync", "reqId": "theirs", "snapshotId": "abc123", "page": 2 });
|
||||
let stamped = stamp(body, "perm.inventory", "r-7").expect("an object is stamped");
|
||||
|
||||
assert_eq!(stamped["cmd"], "perm.inventory");
|
||||
assert_eq!(stamped["reqId"], "r-7");
|
||||
assert_eq!(stamped["snapshotId"], "abc123");
|
||||
assert_eq!(stamped["page"], 2);
|
||||
assert!(stamp(json!([0]), "perm.inventory", "r-8").is_none());
|
||||
}
|
||||
|
||||
/// 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