pub struct SubstrateService { /* private fields */ }Expand description
Substrate RPC service.
Implementations§
Source§impl SubstrateService
impl SubstrateService
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new service with ADR-057 boot-default ACLs for the
local mesh id "local". Prefer Self::with_mesh_id when the
real mesh id is known at construction.
Sourcepub fn with_mesh_id(mesh_id: impl Into<String>) -> Self
pub fn with_mesh_id(mesh_id: impl Into<String>) -> Self
Create a service seeded with ADR-057 defaults for mesh_id.
Sourcepub fn set_acl_table(&self, table: AclTable)
pub fn set_acl_table(&self, table: AclTable)
Replace the ACL table (tests / mesh re-bootstrap).
Sourcepub fn publish_public(&self, path: &str, value: Value) -> u64
pub fn publish_public(&self, path: &str, value: Value) -> u64
Opt a path into public readability (ADR-057 publish_public).
Seals allow: ["public"] on the exact path and publishes
value under the legacy ungated publish path. Prefer the
signed Self::publish_gated flow for production node writes;
this helper is the ergonomic opt-out of default-private sensor
posture after a successful gated publish.
Sourcepub fn take_acl_denials(&self) -> Vec<AclDenialEvent>
pub fn take_acl_denials(&self) -> Vec<AclDenialEvent>
Drain buffered ACL denial events (for ExoChain append by the daemon dispatch loop). Authenticated denials only.
Sourcepub fn declare(&self, path: &str, sensitivity: Sensitivity)
pub fn declare(&self, path: &str, sensitivity: Sensitivity)
Declare (or re-declare) the sensitivity level for a path.
If the path already exists, the declaration is updated in
place without clearing the value. Paths not declared default
to Sensitivity::Workspace on first touch.
Sourcepub fn has_published_under(&self, prefix: &str) -> bool
pub fn has_published_under(&self, prefix: &str) -> bool
Daemon-internal existence check: has anything been published at or
under prefix? Acts as no principal and reads no values, so callers
(discovery, health) need not impersonate a node to ask. It is not an
egress path and must not be exposed over RPC.
Sourcepub fn egress_check(
&self,
caller: Option<&str>,
path: &str,
op: &str,
) -> Result<(), EgressDenied>
pub fn egress_check( &self, caller: Option<&str>, path: &str, op: &str, ) -> Result<(), EgressDenied>
Egress gate: ADR-057 path ACL then sensitivity tier.
This is intentionally the one seam the policy will gate, so callers need not change when grants land for Capture.
Sourcepub fn read(
&self,
caller: Option<&str>,
path: &str,
) -> Result<SubstrateReadSnapshot, EgressDenied>
pub fn read( &self, caller: Option<&str>, path: &str, ) -> Result<SubstrateReadSnapshot, EgressDenied>
Read the current value + metadata at a path.
Sourcepub fn list(
&self,
caller: Option<&str>,
prefix: &str,
depth: u32,
) -> Result<SubstrateListSnapshot, EgressDenied>
pub fn list( &self, caller: Option<&str>, prefix: &str, depth: u32, ) -> Result<SubstrateListSnapshot, EgressDenied>
Enumerate children of a prefix up to depth levels below it.
Contract (ADR-Explorer Phase 1 §3.1):
prefix— substrate path; empty string or"/"means “top-level”. Trailing slashes are trimmed.depth = 0— return only the prefix node itself, if it is a value (no children enumerated).depth = 1— one level belowprefix. Default for the Explorer lazy-tree walk.depth = N > 1— up to N levels belowprefix(flat list, deepest-child first in sort order).
Only paths with a published Replace value participate — pure
internal nodes (no value of their own but with descendants that
do) are still surfaced as entries with has_value: false when
they sit on the path down to a value-bearing leaf; see
child_count semantics on SubstrateListEntry.
Per-child egress: the prefix itself is egress_check’d once
under op "list". Each candidate descendant path is then also
egress-checked so capture-tier path names don’t leak to an
anonymous caller — matching the spirit of read’s per-path gate.
Not a hot path (the Explorer expands one prefix per user click); a full DashMap scan is fine for the foreseeable substrate size.
Sourcepub fn publish_gated(
&self,
node_id: Option<&str>,
path: &str,
value: Value,
) -> Result<u64, GateDenied>
pub fn publish_gated( &self, node_id: Option<&str>, path: &str, value: Value, ) -> Result<u64, GateDenied>
Publish a Replace delta under the node-identity write gate.
Every node-private substrate write belongs to exactly one
node, and may only land under that node’s namespace —
substrate/<node-id>/…. This is the enforcement seam: callers
provide the node_id they have already authenticated
(signature verified at the RPC boundary, or trusted at
in-process call sites where the daemon stamps its own id);
publish_gated refuses to write anywhere else.
Mesh-canonical writes (substrate/_derived/...) are
rejected by this method — the legacy gate has no
crate::NodeRegistry handle and cannot consult the
DerivedWriteGrant table. Use
Self::publish_gated_with_grants for that tier.
Returns the new tick on success, or GateDenied when the
path is outside the node’s prefix or no node id was supplied.
See crate::node_registry::path_belongs_to for the exact
rule.
Fans out to all external-stream subscribers registered via
Self::subscribe.
Sourcepub fn publish_gated_with_grants(
&self,
node_id: Option<&str>,
path: &str,
value: Value,
node_registry: &NodeRegistry,
) -> Result<u64, GateDenied>
pub fn publish_gated_with_grants( &self, node_id: Option<&str>, path: &str, value: Value, node_registry: &NodeRegistry, ) -> Result<u64, GateDenied>
Tier-aware publish gate.
Splits writes by path tier per
.planning/sensors/PIPELINE-PRIMITIVE-JOURNAL.md §R3.3:
- Node-private (
substrate/<node-id>/...) — strict prefix match, identical toSelf::publish_gated. - Mesh-canonical (
substrate/_derived/...) — checks the registry’scrate::DerivedWriteGranttable.node_registry.has_derived_grant(node_id, path)must returntrue. Without a grant the write is rejected withGateDenied::MissingDerivedGrant.
The dual-tier check is the load-bearing bit of R3 — it lets a
daemon-class node publish whisper transcripts at
substrate/_derived/transcript/<source>/mic while still
honouring the per-node prefix rule for everything else.
Sourcepub fn publish(&self, caller: Option<&str>, path: &str, value: Value) -> u64
pub fn publish(&self, caller: Option<&str>, path: &str, value: Value) -> u64
Publish a Replace delta at a path. Returns the new tick.
Fans out to all external-stream subscribers registered via
Self::subscribe. For bring-up, the owner-check is trusted
— the daemon layer should gate on its own agent role policy.
Legacy path. This is the pre-node-identity surface. New
callers should use Self::publish_gated so the per-node
prefix invariant holds. Phased migration lets existing in-
process publishers keep working until they’re each updated.
Sourcepub fn notify(&self, caller: Option<&str>, path: &str) -> u64
pub fn notify(&self, caller: Option<&str>, path: &str) -> u64
Emit a notify-only signal (no payload change) on a path. Returns the current tick (unchanged if no write has happened).
Sourcepub fn subscribe(
&self,
caller: Option<&str>,
path: &str,
) -> Result<(SubscriberId, Receiver<Vec<u8>>), EgressDenied>
pub fn subscribe( &self, caller: Option<&str>, path: &str, ) -> Result<(SubscriberId, Receiver<Vec<u8>>), EgressDenied>
Subscribe an external streaming sink to updates on a path.
Returns the subscriber id and a channel receiver. The caller pipes the JSON lines the sink receives into their socket.
Sourcepub fn unsubscribe(&self, path: &str, id: SubscriberId)
pub fn unsubscribe(&self, path: &str, id: SubscriberId)
Remove a specific subscription. Safe if the id is unknown.
Sourcepub fn path_count(&self) -> usize
pub fn path_count(&self) -> usize
Number of declared paths (for metrics / tests).
Trait Implementations§
Source§impl Clone for SubstrateService
impl Clone for SubstrateService
Auto Trait Implementations§
impl !RefUnwindSafe for SubstrateService
impl !UnwindSafe for SubstrateService
impl Freeze for SubstrateService
impl Send for SubstrateService
impl Sync for SubstrateService
impl Unpin for SubstrateService
impl UnsafeUnpin for SubstrateService
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more