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:
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