lib

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

lib.rs (9355B)


      1 #![forbid(unsafe_code)]
      2 
      3 use radroots_mesh::{
      4     RADROOTS_MESH_RETICULUM_POLICY_ID, RADROOTS_MESH_UNAVAILABLE_MESSAGE, RadrootsMeshPayloadPolicy,
      5 };
      6 use radroots_mesh_agent_proto::{
      7     RADROOTS_MESH_AGENT_SCHEMA_ID, RADROOTS_MESH_AGENT_SCHEMA_NAMESPACE, schema_sha256_hex,
      8 };
      9 use radroots_transport::TransportId;
     10 use radroots_transport::target::TargetScope;
     11 use radroots_transport_reticulum::{RADROOTS_RETICULUM_ENDPOINT_URI, RADROOTS_RETICULUM_SCOPE_ID};
     12 
     13 pub const RADROOTS_MESH_AGENT_CLIENT_SCHEMA_ID: &str = RADROOTS_MESH_AGENT_SCHEMA_ID;
     14 pub const RADROOTS_MESH_AGENT_CLIENT_SCHEMA_NAMESPACE: &str = RADROOTS_MESH_AGENT_SCHEMA_NAMESPACE;
     15 
     16 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     17 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
     18 #[derive(Clone, Debug, PartialEq, Eq)]
     19 pub struct MeshAgentStatusRequest {
     20     pub include_transports: bool,
     21 }
     22 
     23 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     24 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
     25 #[derive(Clone, Debug, PartialEq, Eq)]
     26 pub struct MeshAgentStatusResponse {
     27     pub transports: Vec<MeshAgentTransportStatus>,
     28 }
     29 
     30 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     31 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
     32 #[derive(Clone, Debug, PartialEq, Eq)]
     33 pub struct MeshAgentTransportStatus {
     34     pub transport: MeshAgentTransportKind,
     35     pub profile_id: String,
     36     pub endpoint_uri: String,
     37     pub configured: bool,
     38     pub implementation: MeshAgentImplementation,
     39     pub maturity: MeshAgentCapabilityMaturity,
     40     pub availability: MeshAgentCapabilityAvailability,
     41     pub usable_for_delivery: bool,
     42     pub message: String,
     43 }
     44 
     45 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     46 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
     47 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
     48 pub enum MeshAgentImplementation {
     49     Real,
     50     Mock,
     51 }
     52 
     53 impl MeshAgentImplementation {
     54     pub fn schema_name(self) -> &'static str {
     55         match self {
     56             Self::Real => "real",
     57             Self::Mock => "mock",
     58         }
     59     }
     60 }
     61 
     62 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     63 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
     64 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
     65 pub enum MeshAgentCapabilityMaturity {
     66     Preview,
     67     Stable,
     68 }
     69 
     70 impl MeshAgentCapabilityMaturity {
     71     pub fn schema_name(self) -> &'static str {
     72         match self {
     73             Self::Preview => "preview",
     74             Self::Stable => "stable",
     75         }
     76     }
     77 }
     78 
     79 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     80 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
     81 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
     82 pub enum MeshAgentCapabilityAvailability {
     83     Available,
     84     Degraded,
     85     Unavailable,
     86 }
     87 
     88 impl MeshAgentCapabilityAvailability {
     89     pub fn schema_name(self) -> &'static str {
     90         match self {
     91             Self::Available => "available",
     92             Self::Degraded => "degraded",
     93             Self::Unavailable => "unavailable",
     94         }
     95     }
     96 }
     97 
     98 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
     99 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
    100 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    101 pub enum MeshAgentTransportKind {
    102     Reticulum,
    103 }
    104 
    105 impl MeshAgentTransportKind {
    106     pub fn schema_name(self) -> &'static str {
    107         match self {
    108             Self::Reticulum => "reticulum",
    109         }
    110     }
    111 
    112     pub fn transport_kind(self) -> TransportId {
    113         match self {
    114             Self::Reticulum => TransportId::RETICULUM,
    115         }
    116     }
    117 }
    118 
    119 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
    120 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
    121 #[derive(Clone, Debug, PartialEq, Eq)]
    122 pub struct MeshAgentPublishRequest {
    123     pub publish_request_id: String,
    124     pub payload_cbor: Vec<u8>,
    125     pub event_id: String,
    126     pub target_fingerprint: String,
    127 }
    128 
    129 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
    130 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
    131 #[derive(Clone, Debug, PartialEq, Eq)]
    132 pub struct MeshAgentPublishResponse {
    133     pub publish_request_id: String,
    134     pub status: MeshAgentResponseStatus,
    135     pub transport_receipts: Vec<MeshAgentTransportReceipt>,
    136     pub event_id: String,
    137 }
    138 
    139 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
    140 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
    141 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    142 pub enum MeshAgentResponseStatus {
    143     Accepted,
    144     Deferred,
    145     Rejected,
    146 }
    147 
    148 impl MeshAgentResponseStatus {
    149     pub fn schema_name(self) -> &'static str {
    150         match self {
    151             Self::Accepted => "accepted",
    152             Self::Deferred => "deferred",
    153             Self::Rejected => "rejected",
    154         }
    155     }
    156 }
    157 
    158 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
    159 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
    160 #[derive(Clone, Debug, PartialEq, Eq)]
    161 pub struct MeshAgentTransportReceipt {
    162     pub transport_kind: MeshAgentTransportKind,
    163     pub endpoint_uri: String,
    164     pub outcome: MeshAgentTransportOutcome,
    165     pub message: String,
    166 }
    167 
    168 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
    169 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
    170 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
    171 pub enum MeshAgentTransportOutcome {
    172     Accepted,
    173     Delivered,
    174     Forwarded,
    175     StoredByGateway,
    176     DeferredUntilImplemented,
    177     Rejected,
    178     RouteUnavailable,
    179     Timeout,
    180     TransportUnavailable,
    181 }
    182 
    183 impl MeshAgentTransportOutcome {
    184     pub fn schema_name(self) -> &'static str {
    185         match self {
    186             Self::Accepted => "accepted",
    187             Self::Delivered => "delivered",
    188             Self::Forwarded => "forwarded",
    189             Self::StoredByGateway => "storedByGateway",
    190             Self::DeferredUntilImplemented => "deferredUntilImplemented",
    191             Self::Rejected => "rejected",
    192             Self::RouteUnavailable => "routeUnavailable",
    193             Self::Timeout => "timeout",
    194             Self::TransportUnavailable => "transportUnavailable",
    195         }
    196     }
    197 
    198     pub fn is_success(self) -> bool {
    199         matches!(
    200             self,
    201             Self::Accepted | Self::Delivered | Self::Forwarded | Self::StoredByGateway
    202         )
    203     }
    204 }
    205 
    206 pub trait RadrootsMeshAgentClient {
    207     fn status(&self, request: MeshAgentStatusRequest) -> MeshAgentStatusResponse;
    208     fn publish(&self, request: MeshAgentPublishRequest) -> MeshAgentPublishResponse;
    209     fn schema_sha256_hex(&self) -> String;
    210 }
    211 
    212 #[derive(Clone, Debug, PartialEq, Eq)]
    213 pub struct RadrootsMockMeshAgentClient {
    214     profile_id: String,
    215     endpoint_uri: String,
    216     scope: TargetScope,
    217     policy: RadrootsMeshPayloadPolicy,
    218 }
    219 
    220 impl RadrootsMockMeshAgentClient {
    221     pub fn reticulum_unavailable() -> Self {
    222         Self {
    223             profile_id: RADROOTS_MESH_RETICULUM_POLICY_ID.to_owned(),
    224             endpoint_uri: RADROOTS_RETICULUM_ENDPOINT_URI.to_owned(),
    225             scope: TargetScope::parse(RADROOTS_RETICULUM_SCOPE_ID).expect("Reticulum scope"),
    226             policy: RadrootsMeshPayloadPolicy::reticulum_unavailable(),
    227         }
    228     }
    229 
    230     pub fn scope(&self) -> &TargetScope {
    231         &self.scope
    232     }
    233 
    234     pub fn policy(&self) -> &RadrootsMeshPayloadPolicy {
    235         &self.policy
    236     }
    237 }
    238 
    239 impl Default for RadrootsMockMeshAgentClient {
    240     fn default() -> Self {
    241         Self::reticulum_unavailable()
    242     }
    243 }
    244 
    245 impl RadrootsMeshAgentClient for RadrootsMockMeshAgentClient {
    246     fn status(&self, request: MeshAgentStatusRequest) -> MeshAgentStatusResponse {
    247         let transports = if request.include_transports {
    248             vec![MeshAgentTransportStatus {
    249                 transport: MeshAgentTransportKind::Reticulum,
    250                 profile_id: self.profile_id.clone(),
    251                 endpoint_uri: self.endpoint_uri.clone(),
    252                 configured: true,
    253                 implementation: MeshAgentImplementation::Real,
    254                 maturity: MeshAgentCapabilityMaturity::Preview,
    255                 availability: MeshAgentCapabilityAvailability::Unavailable,
    256                 usable_for_delivery: false,
    257                 message: RADROOTS_MESH_UNAVAILABLE_MESSAGE.to_owned(),
    258             }]
    259         } else {
    260             Vec::new()
    261         };
    262         MeshAgentStatusResponse { transports }
    263     }
    264 
    265     fn publish(&self, request: MeshAgentPublishRequest) -> MeshAgentPublishResponse {
    266         MeshAgentPublishResponse {
    267             publish_request_id: request.publish_request_id,
    268             status: MeshAgentResponseStatus::Rejected,
    269             transport_receipts: vec![MeshAgentTransportReceipt {
    270                 transport_kind: MeshAgentTransportKind::Reticulum,
    271                 endpoint_uri: self.endpoint_uri.clone(),
    272                 outcome: MeshAgentTransportOutcome::TransportUnavailable,
    273                 message: RADROOTS_MESH_UNAVAILABLE_MESSAGE.to_owned(),
    274             }],
    275             event_id: request.event_id,
    276         }
    277     }
    278 
    279     fn schema_sha256_hex(&self) -> String {
    280         schema_sha256_hex()
    281     }
    282 }