lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 33630bb261d12e3d1a87ae48e03df6d2f7ba0b58
parent 4680f9fabdcd40af584002f7c08372a3fc899ce2
Author: triesap <tyson@radroots.org>
Date:   Wed,  8 Jul 2026 06:17:07 +0000

transport: align status observation and mesh contracts

Diffstat:
Mcrates/event_store/src/model.rs | 26+++++++++++++-------------
Mcrates/event_store/src/store.rs | 8++++----
Mcrates/mesh_agent_proto/schema/radroots_mesh_agent_v1.capnp | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/mesh_agent_proto/src/lib.rs | 34++++++++++++++++++++++++++++++++++
Mcrates/mesh_agent_proto/tests/schema.rs | 54+++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mcrates/transport/src/lib.rs | 5++++-
Mcrates/transport/src/status.rs | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mcrates/transport/tests/transport.rs | 38++++++++++++++++++++++++++++++++++----
Mcrates/transport_nostr/src/fetch.rs | 4++--
Mcrates/transport_nostr/src/outbox.rs | 2+-
Mcrates/transport_nostr/tests/transport.rs | 4++--
Mcrates/transport_reticulum/src/lib.rs | 27+++++++++++----------------
Mcrates/transport_reticulum/tests/reticulum_preview.rs | 27++++++++++++++++++++-------
13 files changed, 307 insertions(+), 52 deletions(-)

diff --git a/crates/event_store/src/model.rs b/crates/event_store/src/model.rs @@ -129,9 +129,9 @@ impl StoredEventClass { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RadrootsTransportObservationType { - NostrFetch, - NostrSubscription, - NostrPublishAck, + Fetch, + Subscription, + PublishAck, LocalImport, MeshHeard, MeshForwarded, @@ -144,9 +144,9 @@ pub enum RadrootsTransportObservationType { impl RadrootsTransportObservationType { pub fn as_str(self) -> &'static str { match self { - Self::NostrFetch => "nostr_fetch", - Self::NostrSubscription => "nostr_subscription", - Self::NostrPublishAck => "nostr_publish_ack", + Self::Fetch => "fetch", + Self::Subscription => "subscription", + Self::PublishAck => "publish_ack", Self::LocalImport => "local_import", Self::MeshHeard => "mesh_heard", Self::MeshForwarded => "mesh_forwarded", @@ -159,9 +159,9 @@ impl RadrootsTransportObservationType { pub fn parse(value: &str) -> Result<Self, RadrootsEventStoreError> { match value { - "nostr_fetch" => Ok(Self::NostrFetch), - "nostr_subscription" => Ok(Self::NostrSubscription), - "nostr_publish_ack" => Ok(Self::NostrPublishAck), + "fetch" => Ok(Self::Fetch), + "subscription" => Ok(Self::Subscription), + "publish_ack" => Ok(Self::PublishAck), "local_import" => Ok(Self::LocalImport), "mesh_heard" => Ok(Self::MeshHeard), "mesh_forwarded" => Ok(Self::MeshForwarded), @@ -488,9 +488,9 @@ mod tests { assert!(StoredEventClass::parse("bad").is_err()); for observation_type in [ - RadrootsTransportObservationType::NostrFetch, - RadrootsTransportObservationType::NostrSubscription, - RadrootsTransportObservationType::NostrPublishAck, + RadrootsTransportObservationType::Fetch, + RadrootsTransportObservationType::Subscription, + RadrootsTransportObservationType::PublishAck, RadrootsTransportObservationType::LocalImport, RadrootsTransportObservationType::MeshHeard, RadrootsTransportObservationType::MeshForwarded, @@ -509,7 +509,7 @@ mod tests { let observation = RadrootsTransportObservation::new( RadrootsTransportKind::Nostr, "wss://relay.example.test", - RadrootsTransportObservationType::NostrFetch, + RadrootsTransportObservationType::Fetch, 1, ) .expect("observation") diff --git a/crates/event_store/src/store.rs b/crates/event_store/src/store.rs @@ -1040,7 +1040,7 @@ mod tests { let observation = RadrootsTransportObservation::new( RadrootsTransportKind::Nostr, "wss://relay.example.com", - crate::RadrootsTransportObservationType::NostrPublishAck, + crate::RadrootsTransportObservationType::PublishAck, 1_100, ) .expect("observation"); @@ -1836,7 +1836,7 @@ mod tests { let observation = RadrootsTransportObservation::new( RadrootsTransportKind::Nostr, "wss://relay.local", - crate::RadrootsTransportObservationType::NostrSubscription, + crate::RadrootsTransportObservationType::Subscription, 4_000, ) .expect("observation"); @@ -1845,7 +1845,7 @@ mod tests { let observation = RadrootsTransportObservation::new( RadrootsTransportKind::Nostr, "wss://relay.local", - crate::RadrootsTransportObservationType::NostrSubscription, + crate::RadrootsTransportObservationType::Subscription, 4_100, ) .expect("observation") @@ -1862,7 +1862,7 @@ mod tests { assert_eq!(observations[0].endpoint_uri.as_str(), "wss://relay.local"); assert_eq!( observations[0].observation_type, - crate::RadrootsTransportObservationType::NostrSubscription + crate::RadrootsTransportObservationType::Subscription ); assert_eq!(observations[0].observation_count, 2); assert_eq!(observations[0].first_observed_at_ms, 4_000); diff --git a/crates/mesh_agent_proto/schema/radroots_mesh_agent_v1.capnp b/crates/mesh_agent_proto/schema/radroots_mesh_agent_v1.capnp @@ -8,12 +8,16 @@ struct MeshAgentRequest { requestId @0 :Text; action @1 :MeshAgentAction; frameCbor @2 :Data; + statusRequest @3 :MeshAgentStatusRequest; + publishRequest @4 :MeshAgentPublishRequest; } enum MeshAgentAction { validateFrame @0; stageDelivery @1; observeEventHead @2; + status @3; + publish @4; } struct MeshAgentResponse { @@ -21,6 +25,8 @@ struct MeshAgentResponse { status @1 :MeshAgentResponseStatus; receipt @2 :MeshAgentReceipt; errors @3 :List(MeshAgentError); + statusResponse @4 :MeshAgentStatusResponse; + publishResponse @5 :MeshAgentPublishResponse; } enum MeshAgentResponseStatus { @@ -34,6 +40,59 @@ struct MeshAgentReceipt { acceptedEventHeads @1 :List(Text); } +struct MeshAgentStatusRequest { + includeTransports @0 :Bool; +} + +struct MeshAgentStatusResponse { + readiness @0 :MeshAgentReadinessState; + implementationState @1 :MeshAgentImplementationState; + transports @2 :List(MeshAgentTransportStatus); +} + +struct MeshAgentTransportStatus { + transportKind @0 :Text; + profileId @1 :Text; + endpointUri @2 :Text; + readiness @3 :MeshAgentReadinessState; + implementationState @4 :MeshAgentImplementationState; + publishUsable @5 :Bool; + fetchUsable @6 :Bool; + redactedMessage @7 :Text; +} + +enum MeshAgentReadinessState { + ready @0; + disabled @1; + misconfigured @2; + previewUnavailable @3; +} + +enum MeshAgentImplementationState { + available @0; + disabled @1; + misconfigured @2; + previewUnavailable @3; +} + +struct MeshAgentPublishRequest { + publishRequestId @0 :Text; + payloadCbor @1 :Data; +} + +struct MeshAgentPublishResponse { + publishRequestId @0 :Text; + status @1 :MeshAgentResponseStatus; + transportReceipts @2 :List(MeshAgentTransportReceipt); +} + +struct MeshAgentTransportReceipt { + transportKind @0 :Text; + endpointUri @1 :Text; + deliveryStatus @2 :Text; + redactedMessage @3 :Text; +} + struct MeshAgentError { code @0 :Text; message @1 :Text; diff --git a/crates/mesh_agent_proto/src/lib.rs b/crates/mesh_agent_proto/src/lib.rs @@ -19,6 +19,8 @@ pub enum RadrootsMeshAgentProtoError { MissingAction, MissingResponse, MissingReceipt, + MissingStatusSurface, + MissingPublishSurface, MissingError, } @@ -31,6 +33,12 @@ impl fmt::Display for RadrootsMeshAgentProtoError { Self::MissingAction => f.write_str("mesh agent action schema is missing"), Self::MissingResponse => f.write_str("mesh agent response schema is missing"), Self::MissingReceipt => f.write_str("mesh agent receipt schema is missing"), + Self::MissingStatusSurface => { + f.write_str("mesh agent status schema surface is missing") + } + Self::MissingPublishSurface => { + f.write_str("mesh agent publish schema surface is missing") + } Self::MissingError => f.write_str("mesh agent error schema is missing"), } } @@ -70,6 +78,8 @@ pub fn validate_schema_text(schema: &str) -> Result<(), RadrootsMeshAgentProtoEr || !schema.contains("validateFrame @0;") || !schema.contains("stageDelivery @1;") || !schema.contains("observeEventHead @2;") + || !schema.contains("status @3;") + || !schema.contains("publish @4;") { return Err(RadrootsMeshAgentProtoError::MissingAction); } @@ -83,6 +93,30 @@ pub fn validate_schema_text(schema: &str) -> Result<(), RadrootsMeshAgentProtoEr { return Err(RadrootsMeshAgentProtoError::MissingReceipt); } + if !schema.contains("struct MeshAgentStatusRequest") + || !schema.contains("struct MeshAgentStatusResponse") + || !schema.contains("enum MeshAgentReadinessState") + || !schema.contains("enum MeshAgentImplementationState") + || !schema.contains("struct MeshAgentTransportStatus") + || !schema.contains("includeTransports @0 :Bool;") + || !schema.contains("readiness @0 :MeshAgentReadinessState;") + || !schema.contains("implementationState @1 :MeshAgentImplementationState;") + || !schema.contains("publishUsable @5 :Bool;") + || !schema.contains("fetchUsable @6 :Bool;") + || !schema.contains("previewUnavailable @3;") + { + return Err(RadrootsMeshAgentProtoError::MissingStatusSurface); + } + if !schema.contains("struct MeshAgentPublishRequest") + || !schema.contains("struct MeshAgentPublishResponse") + || !schema.contains("struct MeshAgentTransportReceipt") + || !schema.contains("publishRequest @4 :MeshAgentPublishRequest;") + || !schema.contains("publishResponse @5 :MeshAgentPublishResponse;") + || !schema.contains("publishRequestId @0 :Text;") + || !schema.contains("transportReceipts @2 :List(MeshAgentTransportReceipt);") + { + return Err(RadrootsMeshAgentProtoError::MissingPublishSurface); + } if !schema.contains("struct MeshAgentError") { return Err(RadrootsMeshAgentProtoError::MissingError); } diff --git a/crates/mesh_agent_proto/tests/schema.rs b/crates/mesh_agent_proto/tests/schema.rs @@ -12,6 +12,10 @@ fn schema_declares_mesh_agent_v1_surface() { assert!(RADROOTS_MESH_AGENT_SCHEMA.contains(RADROOTS_MESH_AGENT_SCHEMA_NAMESPACE)); assert!(RADROOTS_MESH_AGENT_SCHEMA.contains("struct MeshAgentRequest")); assert!(RADROOTS_MESH_AGENT_SCHEMA.contains("struct MeshAgentResponse")); + assert!(RADROOTS_MESH_AGENT_SCHEMA.contains("struct MeshAgentStatusRequest")); + assert!(RADROOTS_MESH_AGENT_SCHEMA.contains("struct MeshAgentStatusResponse")); + assert!(RADROOTS_MESH_AGENT_SCHEMA.contains("struct MeshAgentPublishRequest")); + assert!(RADROOTS_MESH_AGENT_SCHEMA.contains("struct MeshAgentPublishResponse")); } #[test] @@ -22,7 +26,7 @@ fn schema_hash_is_deterministic() { assert_eq!(first, second); assert_eq!( first, - "ceaaa2968805a21c9f08b76b22ac45ae819312ee595a60675f560ec81d6f8fe0" + "ea82bfc39ae963baf260a6c626ca9033767b0fec93aa013101f975e39baeae6a" ); } @@ -72,6 +76,14 @@ fn schema_validator_reports_each_missing_required_surface() { RadrootsMeshAgentProtoError::MissingAction, ), ( + valid.replace("status @3;", "agentStatus @3;"), + RadrootsMeshAgentProtoError::MissingAction, + ), + ( + valid.replace("publish @4;", "publishSomethingElse @4;"), + RadrootsMeshAgentProtoError::MissingAction, + ), + ( valid.replace( "struct MeshAgentResponse", "struct MissingMeshAgentResponse", @@ -97,6 +109,38 @@ fn schema_validator_reports_each_missing_required_surface() { RadrootsMeshAgentProtoError::MissingReceipt, ), ( + valid.replace( + "struct MeshAgentStatusRequest", + "struct MissingMeshAgentStatusRequest", + ), + RadrootsMeshAgentProtoError::MissingStatusSurface, + ), + ( + valid.replace( + "enum MeshAgentReadinessState", + "enum MissingMeshAgentReadinessState", + ), + RadrootsMeshAgentProtoError::MissingStatusSurface, + ), + ( + valid.replace( + "implementationState @1 :MeshAgentImplementationState;", + "implementation @1 :MeshAgentImplementationState;", + ), + RadrootsMeshAgentProtoError::MissingStatusSurface, + ), + ( + valid.replace( + "struct MeshAgentPublishRequest", + "struct MissingMeshAgentPublishRequest", + ), + RadrootsMeshAgentProtoError::MissingPublishSurface, + ), + ( + valid.replace("publishRequestId @0 :Text;", "operationId @0 :Text;"), + RadrootsMeshAgentProtoError::MissingPublishSurface, + ), + ( valid.replace("struct MeshAgentError", "struct MissingMeshAgentError"), RadrootsMeshAgentProtoError::MissingError, ), @@ -135,6 +179,14 @@ fn mesh_agent_proto_errors_have_stable_display_strings() { "mesh agent receipt schema is missing", ), ( + RadrootsMeshAgentProtoError::MissingStatusSurface, + "mesh agent status schema surface is missing", + ), + ( + RadrootsMeshAgentProtoError::MissingPublishSurface, + "mesh agent publish schema surface is missing", + ), + ( RadrootsMeshAgentProtoError::MissingError, "mesh agent error schema is missing", ), diff --git a/crates/transport/src/lib.rs b/crates/transport/src/lib.rs @@ -20,7 +20,10 @@ pub use kind::{RadrootsTransportImplementationState, RadrootsTransportKind}; pub use message::{ RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, }; -pub use status::{RadrootsTransportDeliveryTargetStatus, RadrootsTransportOutcome}; +pub use status::{ + RadrootsTransportDeliveryTargetStatus, RadrootsTransportOutcome, + RadrootsTransportReadinessState, RadrootsTransportStatus, +}; pub use target::{ RadrootsTransportTarget, RadrootsTransportTargetFingerprint, RadrootsTransportTargetSet, RadrootsTransportTargetUri, diff --git a/crates/transport/src/status.rs b/crates/transport/src/status.rs @@ -1,4 +1,7 @@ -use crate::delivery::RadrootsTransportSatisfactionClass; +use crate::{ + RadrootsTransportImplementationState, RadrootsTransportKind, + delivery::RadrootsTransportSatisfactionClass, +}; use alloc::string::String; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -81,3 +84,69 @@ impl RadrootsTransportOutcome { } } } + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum RadrootsTransportReadinessState { + Ready, + Disabled, + Misconfigured, + PreviewUnavailable, +} + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct RadrootsTransportStatus { + pub kind: RadrootsTransportKind, + pub profile_id: Option<String>, + pub endpoint_uri: Option<String>, + pub implementation_state: RadrootsTransportImplementationState, + pub readiness: RadrootsTransportReadinessState, + pub publish_usable: bool, + pub fetch_usable: bool, + pub redacted_message: Option<String>, +} + +impl RadrootsTransportStatus { + pub fn new( + kind: RadrootsTransportKind, + implementation_state: RadrootsTransportImplementationState, + readiness: RadrootsTransportReadinessState, + ) -> Self { + Self { + kind, + profile_id: None, + endpoint_uri: None, + implementation_state, + readiness, + publish_usable: false, + fetch_usable: false, + redacted_message: None, + } + } + + pub fn with_profile_id(mut self, profile_id: impl Into<String>) -> Self { + self.profile_id = Some(profile_id.into()); + self + } + + pub fn with_endpoint_uri(mut self, endpoint_uri: impl Into<String>) -> Self { + self.endpoint_uri = Some(endpoint_uri.into()); + self + } + + pub fn with_publish_usable(mut self, publish_usable: bool) -> Self { + self.publish_usable = publish_usable; + self + } + + pub fn with_fetch_usable(mut self, fetch_usable: bool) -> Self { + self.fetch_usable = fetch_usable; + self + } + + pub fn with_redacted_message(mut self, redacted_message: impl Into<String>) -> Self { + self.redacted_message = Some(redacted_message.into()); + self + } +} diff --git a/crates/transport/tests/transport.rs b/crates/transport/tests/transport.rs @@ -1,10 +1,11 @@ use radroots_transport::{ RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryRequest, RadrootsTransportDeliveryTargetStatus, - RadrootsTransportError, RadrootsTransportKind, RadrootsTransportOutcome, - RadrootsTransportSatisfactionClass, RadrootsTransportSatisfactionPolicy, - RadrootsTransportTarget, RadrootsTransportTargetFingerprint, RadrootsTransportTargetReceipt, - RadrootsTransportTargetSet, RadrootsTransportTargetUri, + RadrootsTransportError, RadrootsTransportImplementationState, RadrootsTransportKind, + RadrootsTransportOutcome, RadrootsTransportReadinessState, RadrootsTransportSatisfactionClass, + RadrootsTransportSatisfactionPolicy, RadrootsTransportStatus, RadrootsTransportTarget, + RadrootsTransportTargetFingerprint, RadrootsTransportTargetReceipt, RadrootsTransportTargetSet, + RadrootsTransportTargetUri, }; #[test] @@ -158,6 +159,35 @@ fn satisfaction_policy_counts_target_statuses() { } #[test] +fn transport_status_models_generic_readiness_and_usability() { + let status = RadrootsTransportStatus::new( + RadrootsTransportKind::Nostr, + RadrootsTransportImplementationState::Available, + RadrootsTransportReadinessState::Ready, + ) + .with_profile_id("transport.nostr.default") + .with_endpoint_uri("wss://relay.example") + .with_publish_usable(true) + .with_fetch_usable(true) + .with_redacted_message("ready"); + + assert_eq!(status.kind, RadrootsTransportKind::Nostr); + assert_eq!( + status.profile_id.as_deref(), + Some("transport.nostr.default") + ); + assert_eq!(status.endpoint_uri.as_deref(), Some("wss://relay.example")); + assert_eq!( + status.implementation_state, + RadrootsTransportImplementationState::Available + ); + assert_eq!(status.readiness, RadrootsTransportReadinessState::Ready); + assert!(status.publish_usable); + assert!(status.fetch_usable); + assert_eq!(status.redacted_message.as_deref(), Some("ready")); +} + +#[test] fn deferred_transport_outcomes_are_terminal_but_not_satisfied() { let target = RadrootsTransportTarget::new( RadrootsTransportKind::Reticulum, diff --git a/crates/transport_nostr/src/fetch.rs b/crates/transport_nostr/src/fetch.rs @@ -362,9 +362,9 @@ where }) => { let event = radroots_event_from_nostr(&raw_event); let observation_type = match mode { - RadrootsRelayFetchMode::Fetch => RadrootsTransportObservationType::NostrFetch, + RadrootsRelayFetchMode::Fetch => RadrootsTransportObservationType::Fetch, RadrootsRelayFetchMode::Subscription => { - RadrootsTransportObservationType::NostrSubscription + RadrootsTransportObservationType::Subscription } }; let observation = RadrootsTransportObservation::new( diff --git a/crates/transport_nostr/src/outbox.rs b/crates/transport_nostr/src/outbox.rs @@ -378,7 +378,7 @@ async fn ingest_publish_observation( let observation = RadrootsTransportObservation::new( RadrootsTransportKind::Nostr, relay_url, - RadrootsTransportObservationType::NostrPublishAck, + RadrootsTransportObservationType::PublishAck, observed_at_ms, ); let mut observation = observation?; diff --git a/crates/transport_nostr/tests/transport.rs b/crates/transport_nostr/tests/transport.rs @@ -886,7 +886,7 @@ async fn fetch_ingests_events_and_records_transport_observations() { assert_eq!(observations[0].endpoint_uri.as_str(), RELAY_PRIMARY_WSS); assert_eq!( observations[0].observation_type, - RadrootsTransportObservationType::NostrFetch + RadrootsTransportObservationType::Fetch ); assert_eq!(observations[0].observation_count, 2); } @@ -1227,7 +1227,7 @@ async fn fetch_subscription_mode_and_store_errors_are_reported() { assert_eq!(observations.len(), 1); assert_eq!( observations[0].observation_type, - RadrootsTransportObservationType::NostrSubscription + RadrootsTransportObservationType::Subscription ); let closed_store = RadrootsEventStore::open_memory().await.expect("store"); diff --git a/crates/transport_reticulum/src/lib.rs b/crates/transport_reticulum/src/lib.rs @@ -11,8 +11,8 @@ use radroots_transport::{ RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, RadrootsTransportDeliveryReceipt, RadrootsTransportDeliveryRequest, RadrootsTransportDeliveryTargetStatus, RadrootsTransportImplementationState, - RadrootsTransportKind, RadrootsTransportOutcome, RadrootsTransportTarget, - RadrootsTransportTargetReceipt, + RadrootsTransportKind, RadrootsTransportOutcome, RadrootsTransportReadinessState, + RadrootsTransportStatus, RadrootsTransportTarget, RadrootsTransportTargetReceipt, }; const DEFAULT_PROFILE_ID: &str = "transport.reticulum.preview"; @@ -34,12 +34,6 @@ impl Default for RadrootsReticulumPreviewBehavior { } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum RadrootsReticulumPreviewReadiness { - PreviewUnavailable, -} - -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct RadrootsReticulumPreviewEndpoint { uri: String, @@ -130,11 +124,15 @@ impl RadrootsReticulumPreviewProfile { pub fn status(&self) -> RadrootsReticulumPreviewStatus { RadrootsReticulumPreviewStatus { - profile_id: self.profile_id.clone(), - endpoint_uri: self.endpoint.as_str().to_owned(), behavior: self.behavior, - readiness: RadrootsReticulumPreviewReadiness::PreviewUnavailable, - implementation_state: RadrootsTransportImplementationState::PreviewUnavailable, + transport_status: RadrootsTransportStatus::new( + RadrootsTransportKind::Reticulum, + RadrootsTransportImplementationState::PreviewUnavailable, + RadrootsTransportReadinessState::PreviewUnavailable, + ) + .with_profile_id(self.profile_id.clone()) + .with_endpoint_uri(self.endpoint.as_str()) + .with_redacted_message(RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE), } } } @@ -148,11 +146,8 @@ impl Default for RadrootsReticulumPreviewProfile { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct RadrootsReticulumPreviewStatus { - pub profile_id: String, - pub endpoint_uri: String, pub behavior: RadrootsReticulumPreviewBehavior, - pub readiness: RadrootsReticulumPreviewReadiness, - pub implementation_state: RadrootsTransportImplementationState, + pub transport_status: RadrootsTransportStatus, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/crates/transport_reticulum/tests/reticulum_preview.rs b/crates/transport_reticulum/tests/reticulum_preview.rs @@ -1,15 +1,14 @@ use radroots_transport::{ RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE, RadrootsTransportDeliveryRequest, RadrootsTransportDeliveryTargetStatus, - RadrootsTransportImplementationState, RadrootsTransportKind, + RadrootsTransportImplementationState, RadrootsTransportKind, RadrootsTransportReadinessState, RadrootsTransportSatisfactionClass, RadrootsTransportSatisfactionPolicy, RadrootsTransportTarget, RadrootsTransportTargetSet, }; use radroots_transport_reticulum::{ RadrootsReticulumPreviewBehavior, RadrootsReticulumPreviewEndpoint, RadrootsReticulumPreviewError, RadrootsReticulumPreviewFetchRequest, - RadrootsReticulumPreviewProfile, RadrootsReticulumPreviewReadiness, - RadrootsReticulumPreviewTransport, + RadrootsReticulumPreviewProfile, RadrootsReticulumPreviewTransport, }; fn reticulum_target(uri: &str) -> RadrootsTransportTarget { @@ -45,13 +44,27 @@ fn default_profile_is_configured_preview_unavailable_and_rejecting() { RadrootsReticulumPreviewBehavior::RejectDeliveryAttempts ); assert_eq!( - status.implementation_state, + status.transport_status.implementation_state, RadrootsTransportImplementationState::PreviewUnavailable ); assert_eq!( - status.readiness, - RadrootsReticulumPreviewReadiness::PreviewUnavailable + status.transport_status.readiness, + RadrootsTransportReadinessState::PreviewUnavailable ); + assert_eq!( + status.transport_status.profile_id.as_deref(), + Some("transport.reticulum.preview") + ); + assert_eq!( + status.transport_status.endpoint_uri.as_deref(), + Some(RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI) + ); + assert_eq!( + status.transport_status.redacted_message.as_deref(), + Some(RADROOTS_RETICULUM_UNAVAILABLE_MESSAGE) + ); + assert!(!status.transport_status.publish_usable); + assert!(!status.transport_status.fetch_usable); } #[test] @@ -249,7 +262,7 @@ fn fetch_reports_preview_unavailable_without_observed_events() { "transport.reticulum.preview" ); assert_eq!( - transport.status().implementation_state, + transport.status().transport_status.implementation_state, RadrootsTransportImplementationState::PreviewUnavailable ); let receipt = transport