diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ops/core.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ops/core.py | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ops/core.py b/packages/meshbay-node/src/meshbay_node/ops/core.py new file mode 100644 index 0000000..7c19d78 --- /dev/null +++ b/packages/meshbay-node/src/meshbay_node/ops/core.py @@ -0,0 +1,57 @@ +"""What every operation shares: the refusal it raises and the lookups into `state`.""" + +from __future__ import annotations + +from typing import Any + + +class OpError(Exception): + """ + An operation refused, with enough for any adapter to report it. + + `status` is an HTTP code because one adapter needs one; the others ignore it. + `extra` carries the "here is what would have worked" payload — a bare "no + such group" leaves an operator guessing at a UUID. + """ + + def __init__(self, message: str, *, status: int = 400, + extra: dict[str, Any] | None = None): + super().__init__(message) + self.message = message + self.status = status + self.extra = extra or {} + + def as_dict(self) -> dict: + return {"error": self.message, **self.extra} + + +# ── Shared lookups ─────────────────────────────────────────────────────────── + +def _roster(state: dict): + roster = state.get("roster") + if not roster: + raise OpError("Roster not available", status=503) + return roster + + +def _hub(state: dict): + hub = state.get("hub") + if not hub or not hub._session: + raise OpError("Hub not connected", status=503) + return hub + + +def _group_ctx(state: dict, group_id: str) -> dict: + groups_ctx = state.get("groups_ctx", {}) + if group_id not in groups_ctx: + raise OpError("Group not hosted on this node", status=404, + extra={"available": [ + {"id": gid} for gid in groups_ctx]}) + return groups_ctx[group_id] + + +def _config(state: dict): + config = state.get("config") + if not config: + raise OpError("No config loaded", status=503) + return config |