#[non_exhaustive]pub enum StreamFrame {
Snapshot {
active_sessions: Vec<ActiveSession>,
reachability: Vec<PeerReachability>,
self_network: Option<SelfNetwork>,
},
Event {
record: Box<AuditRecord>,
},
Reachability {
peer: PeerReachability,
source: ReachabilitySource,
},
SelfNetwork {
self_network: SelfNetwork,
},
Lagged {
dropped: u64,
},
}Expand description
One frame of the Request::Subscribe stream (pairing liveness & health telemetry). Tagged on
type (snake_case), so a frame is {"type":"snapshot",...} / {"type":"event",...} /
{"type":"lagged",...}. Event.record is the AuditRecord verbatim, so the stream and the
on-disk log carry ONE schema. The daemon serializes these; an embedding consumer deserializes
them (see docs/local-protocol.md “Live event stream”).
#[non_exhaustive]: a future frame kind must not break a downstream match. Adding
Reachability in 0.13.0 DID break exhaustive matches — which is why that release is a MINOR,
per RELEASING.md’s pre-1.0 rule that breaking changes bump the minor. Consumers now write a
_ => arm and later additions are additive for Rust as well as for JSON.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Snapshot
The FIRST frame: a point-in-time picture of the mesh (open sessions + paired-peer reachability) so a fresh subscriber renders immediately without replaying history.
Fields
active_sessions: Vec<ActiveSession>reachability: Vec<PeerReachability>self_network: Option<SelfNetwork>THIS node’s own reachability posture (#90), so a fresh subscriber renders it without
a status poll. None in mesh-less control-only mode. Additive: default +
skip-if-none so an older payload round-trips.
Event
A live audit event (session open/close, request, blob fetch, trust) — the tap on the hub.
Boxed so this (much larger) variant does not bloat every frame; serde delegates through the
Box, so the wire shape is the record’s fields verbatim.
Fields
record: Box<AuditRecord>Reachability
A peer’s reachability TRANSITIONED (#58): it became reachable, became unreachable, or was
probed for the first time. Pushed so an embedder does not have to poll status for a live
online/offline indicator — and so work queued for an unreachable peer can flush the moment
it returns, rather than on the next poll tick.
Emitted on a change of reachable or of path. A refresh with the same verdict AND the
same path emits nothing, so a peer that stays up does not produce a frame per TTL refresh;
rtt_ms/meta/services drift is advisory detail and is not a transition. age_secs is
0 — the observation just completed.
Do not treat this as an up/down toggle. It carried that meaning through 0.18, and this
doc said “on a CHANGE of reachable only” until 1.22 — which stopped being true in 0.19.0
(#92 item 1), when path joined the transition rule. A consumer that assumed same-verdict
frames were impossible was reading a stale guarantee.
Two producers, as of API 1.22 — and since 1.30 source says WHICH ONE, so the distinction
is readable rather than inferred:
ReachabilitySource::Probe— a probe completing (status/subscriberefreshing a stale entry). It describes a throwaway dial, not anyone’s live connection.ReachabilitySource::Session— a live session whose selected path changed under it (#92 item 2). A claim about the link in use.
The second producer is why path is trustworthy for a long-lived session: a session that
degrades Direct→Relay mid-call now says so when it happens, rather than staying silently
mislabelled until something probes. path is a truth claim about where user data went, so
Unknown means “we do not know” and must never be rendered as private.
rtt_ms is not a discriminator, and never was (#150). Until 1.30 this doc said a
session-sourced frame carries rtt_ms: None — true only of a FIRST observation, where no
round trip was measured and none is invented. A session-sourced frame for an
already-probed peer carries that probe’s rtt_ms: Some(..), because the path watcher
deliberately leaves rtt_ms/meta/probed_at alone (refreshing them would stamp a stale
RTT as fresh and suppress the corrective probe — #92 review). That is the common case for a
peer probed at pairing time and then watched through a long call. Read source.
Fields
peer: PeerReachabilitysource: ReachabilitySourceWhich producer emitted this frame (#150). api_minor >= 30.
Additive: #[serde(default)], landing on ReachabilitySource::Unknown — NOT on
Probe. A daemon at api_minor 22–29 already has both producers, so an absent field
genuinely does not say which one ran; defaulting to Probe would assert the wrong
producer for every session-sourced frame such a daemon emits, which is the exact
ambiguity this field exists to remove.
SelfNetwork
THIS node’s own network posture CHANGED (#90): online flipped, the home relay moved,
or a relay’s connection state changed — pushed so an embedder learns “you just went
unreachable” the moment it happens instead of on a poll tick, and so #53’s set_relays
finally has a signal telling someone to use it. direct_addrs drift alone does not
emit (address churn is chatty and not a decision point; it rides the next frame).
api_minor >= 28.
Fields
self_network: SelfNetworkLagged
The subscriber fell dropped records behind the broadcast ring; the stream continues (a
fresh reconnect would re-Snapshot). Never drops the subscriber — lag is reported, never fatal.
Trait Implementations§
Source§impl Clone for StreamFrame
impl Clone for StreamFrame
Source§fn clone(&self) -> StreamFrame
fn clone(&self) -> StreamFrame
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more