Skip to main content

prns_runtime/runtime/
command.rs

1use crate::engine::{
2    AnnounceAppData, AnnounceNow, AnnounceTarget, CommandId, PacketReceiptDelivered, PrnsCommand,
3    SendSinglePacketFailure,
4};
5pub use crate::engine::{DropRouteOutcome, DropRoutesViaOutcome};
6use crate::identity::{
7    IdentityHash, MarkDestinationUsedOutcome, ReleaseDestinationOutcome, RetainDestinationOutcome,
8    RetainIdentityOutcome,
9};
10use crate::routing::links::LinkId;
11use crate::wire::{DestinationHash, TransportId};
12
13use super::request_endpoints::RespondToken;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct ClearAnnounceQueuesOutcome {
17    pub dropped_announces: u32,
18}
19
20/// Why an awaited send never reached `Delivered`.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum SendError<F> {
23    /// The payload was larger than a single packet's MDU — rejected before the wire.
24    PayloadTooLarge,
25    /// The node has stopped: the command channel is closed (host) or the bounded lane is gone.
26    NodeStopped,
27    /// More awaited sends are in flight than the platform tracks at once — the embedded
28    /// `CompletionPool` is full. The unbounded host path never returns it.
29    Busy,
30    /// The engine settled the send as a typed failure (`SendSinglePacketFailure`, …).
31    Failed(F),
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum RoutingControlError {
36    NodeStopped,
37    Busy,
38}
39
40pub trait RoutingControl {
41    fn drop_route(
42        &self,
43        destination: DestinationHash,
44    ) -> impl core::future::Future<Output = Result<DropRouteOutcome, RoutingControlError>> + Send;
45
46    fn drop_routes_via(
47        &self,
48        transport: TransportId,
49    ) -> impl core::future::Future<Output = Result<DropRoutesViaOutcome, RoutingControlError>> + Send;
50
51    fn clear_announce_queues(
52        &self,
53    ) -> impl core::future::Future<Output = Result<ClearAnnounceQueuesOutcome, RoutingControlError>> + Send;
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum DestinationIdentityRetentionControlError {
58    NodeStopped,
59    Busy,
60}
61
62pub trait DestinationIdentityRetentionControl {
63    fn mark_destination_used(
64        &self,
65        destination: DestinationHash,
66    ) -> impl core::future::Future<
67        Output = Result<MarkDestinationUsedOutcome, DestinationIdentityRetentionControlError>,
68    > + Send;
69
70    fn retain_destination(
71        &self,
72        destination: DestinationHash,
73    ) -> impl core::future::Future<
74        Output = Result<RetainDestinationOutcome, DestinationIdentityRetentionControlError>,
75    > + Send;
76
77    fn release_destination(
78        &self,
79        destination: DestinationHash,
80    ) -> impl core::future::Future<
81        Output = Result<ReleaseDestinationOutcome, DestinationIdentityRetentionControlError>,
82    > + Send;
83
84    fn retain_identity(
85        &self,
86        identity: IdentityHash,
87    ) -> impl core::future::Future<
88        Output = Result<RetainIdentityOutcome, DestinationIdentityRetentionControlError>,
89    > + Send;
90}
91
92/// The high-level API shared by every platform's node handle. Tokio carries commands over an unbounded channel with per-command oneshots; Embassy uses a bounded channel and static completion pool. [`issue`](Self::issue) returns a minted [`CommandId`] immediately, while awaited operations settle through that id. Platform-specific capabilities remain inherent methods on the concrete handle.
93#[allow(async_fn_in_trait)]
94pub trait PrnsNodeApi {
95    /// Queue an engine command and return the [`CommandId`] it was minted under — watch the event
96    /// stream for the settlement tagged with it. `None` once the node has stopped (or the bounded
97    /// embedded lane is full). The fire-and-forget escape hatch.
98    fn issue(&self, command: PrnsCommand) -> Option<CommandId>;
99
100    /// Announce `destination` on every interface with its registered app_data: RNS 1.4.2
101    /// `Destination.announce()` with no arguments. `None` once the node has stopped. For one
102    /// interface or explicit app_data, [`issue`](Self::issue) a custom [`AnnounceNow`].
103    fn announce(&self, destination: DestinationHash) -> Option<CommandId> {
104        self.issue(PrnsCommand::AnnounceNow(AnnounceNow {
105            destination,
106            target: AnnounceTarget::AllInterfaces,
107            app_data: AnnounceAppData::Registered,
108        }))
109    }
110
111    /// Send one Single data packet to `destination` and await its delivery proof — `Ok(Delivered)`
112    /// with the measured round trip, or the typed reason it did not deliver.
113    async fn send_single_packet(
114        &self,
115        destination: DestinationHash,
116        data: &[u8],
117    ) -> Result<PacketReceiptDelivered, SendError<SendSinglePacketFailure>>;
118
119    fn respond_packed(&self, responder: RespondToken, packed: &[u8]) -> bool;
120
121    /// Sever an active link. Returns `false` once the node has stopped.
122    fn close_link(&self, link_id: LinkId) -> bool;
123}