Skip to main content

iroh_n0des/
protocol.rs

1use anyhow::Result;
2use irpc::{channel::oneshot, rpc_requests};
3use rcan::Rcan;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::{caps::Caps, net_diagnostics::DiagnosticsReport};
8
9/// The main ALPN for connecting from the client to the cloud node.
10pub const ALPN: &[u8] = b"/iroh/n0des/1";
11
12pub type N0desClient = irpc::Client<N0desProtocol>;
13
14#[rpc_requests(message = N0desMessage)]
15#[derive(Debug, Serialize, Deserialize)]
16#[allow(clippy::large_enum_variant)]
17pub enum N0desProtocol {
18    #[rpc(tx=oneshot::Sender<()>)]
19    Auth(Auth),
20    #[rpc(tx=oneshot::Sender<RemoteResult<()>>)]
21    PutMetrics(PutMetrics),
22    #[rpc(tx=oneshot::Sender<Pong>)]
23    Ping(Ping),
24
25    #[rpc(tx=oneshot::Sender<RemoteResult<()>>)]
26    TicketPublish(PublishTicket),
27    #[rpc(tx=oneshot::Sender<RemoteResult<bool>>)]
28    TicketUnpublish(UnpublishTicket),
29    #[rpc(tx=oneshot::Sender<RemoteResult<Option<TicketData>>>)]
30    TicketGet(GetTicket),
31    #[rpc(tx=oneshot::Sender<RemoteResult<Vec<TicketData>>>)]
32    TicketList(ListTickets),
33
34    #[rpc(tx=oneshot::Sender<RemoteResult<()>>)]
35    PutNetworkDiagnostics(PutNetworkDiagnostics),
36
37    #[rpc(tx=oneshot::Sender<RemoteResult<()>>)]
38    GrantCap(GrantCap),
39}
40
41/// Dedicated protocol for cloud-to-endpoint net diagnostics connections.
42#[rpc_requests(message = NetDiagnosticsMessage)]
43#[derive(Debug, Serialize, Deserialize)]
44#[allow(clippy::large_enum_variant)]
45pub enum ClientHostProtocol {
46    #[rpc(tx=oneshot::Sender<()>)]
47    Auth(Auth),
48    #[rpc(tx=oneshot::Sender<RemoteResult<DiagnosticsReport>>)]
49    RunNetworkDiagnostics(RunNetworkDiagnostics),
50}
51
52pub type RemoteResult<T> = Result<T, RemoteError>;
53
54#[derive(Clone, Serialize, Deserialize, thiserror::Error, Debug)]
55pub enum RemoteError {
56    #[error("Missing capability: {}", _0.to_strings().join(", "))]
57    MissingCapability(Caps),
58    #[error("Unauthorized: {}", _0)]
59    AuthError(String),
60    #[error("Internal server error")]
61    InternalServerError,
62}
63
64/// Authentication on first request
65#[derive(Debug, Serialize, Deserialize)]
66pub struct Auth {
67    pub caps: Rcan<Caps>,
68}
69
70/// Request to store the given metrics data
71#[derive(Debug, Serialize, Deserialize)]
72pub struct PutMetrics {
73    pub session_id: Uuid,
74    pub update: iroh_metrics::encoding::Update,
75}
76
77/// Simple ping requests
78#[derive(Debug, Serialize, Deserialize)]
79pub struct Ping {
80    pub req_id: [u8; 16],
81}
82
83/// Simple ping response
84#[derive(Debug, Serialize, Deserialize)]
85pub struct Pong {
86    pub req_id: [u8; 16],
87}
88
89/// Publishing a ticket allows n0des to act as a central hub to ferry tickets
90/// between endpoints.
91#[derive(Debug, Serialize, Deserialize)]
92pub struct PublishTicket {
93    pub req_id: [u8; 16],
94    pub name: String,
95    pub ticket_kind: String,
96    pub ticket: Vec<u8>,
97}
98
99/// wire-level request to remove a ticket. Useful for undos, and any situation
100/// where the uptime of the endpoint outlasts the utility of the ticket.
101#[derive(Debug, Serialize, Deserialize)]
102pub struct UnpublishTicket {
103    pub req_id: [u8; 16],
104    pub name: String,
105    pub ticket_kind: String,
106}
107
108/// wire-level request get a ticket by name.
109#[derive(Debug, Serialize, Deserialize)]
110pub struct GetTicket {
111    pub req_id: [u8; 16],
112    pub name: String,
113    pub ticket_kind: String,
114}
115
116/// Wire format for requesting a list of tickets
117#[derive(Debug, Serialize, Deserialize)]
118pub struct ListTickets {
119    pub req_id: [u8; 16],
120    pub ticket_kind: String,
121    pub offset: u32,
122    pub limit: u32,
123}
124
125/// Signals are opaque data that n0des can ferry between endpoints
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct TicketData {
128    pub name: String,
129    pub ticket_kind: String,
130    pub ticket_bytes: Vec<u8>,
131}
132
133impl From<PublishTicket> for TicketData {
134    fn from(msg: PublishTicket) -> Self {
135        TicketData {
136            name: msg.name,
137            ticket_kind: msg.ticket_kind,
138            ticket_bytes: msg.ticket,
139        }
140    }
141}
142
143/// Publishing network diagnostics
144#[derive(Debug, Serialize, Deserialize)]
145pub struct PutNetworkDiagnostics {
146    pub report: crate::net_diagnostics::DiagnosticsReport,
147}
148
149/// ask this node to run diagnostics & return the result.
150/// present even without the net_diagnostics feature flag because the request
151/// struct is empty in both cases
152#[derive(Debug, Serialize, Deserialize)]
153pub struct RunNetworkDiagnostics;
154
155/// Grant a capability token to the remote endpoint. The remote should store
156/// the RCAN and use it when dialing back to authorize its requests.
157#[derive(Debug, Serialize, Deserialize)]
158pub struct GrantCap {
159    pub cap: Rcan<Caps>,
160}