iroh_n0des/
ticket.rs

1use std::{
2    collections::BTreeSet,
3    fmt::{self, Display},
4    str::FromStr,
5};
6
7use iroh::{EndpointAddr, EndpointId, SecretKey, TransportAddr};
8use iroh_tickets::{ParseError, Ticket};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone)]
12pub struct N0desTicket {
13    /// secret use to construct rcans from
14    pub secret: SecretKey,
15    /// the n0des endpoint to direct requests to
16    pub remote: EndpointAddr,
17}
18
19impl Display for N0desTicket {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        write!(f, "{}", Ticket::serialize(self))
22    }
23}
24
25#[derive(Serialize, Deserialize)]
26struct Variant0NodeAddr {
27    endpoint_id: EndpointId,
28    info: Variant0AddrInfo,
29}
30
31#[derive(Serialize, Deserialize)]
32struct Variant0AddrInfo {
33    addrs: BTreeSet<TransportAddr>,
34}
35
36/// Wire format for [`NodeTicket`].
37#[derive(Serialize, Deserialize)]
38enum TicketWireFormat {
39    Variant0(Variant0N0desTicket),
40}
41
42#[derive(Serialize, Deserialize)]
43struct Variant0N0desTicket {
44    secret: SecretKey,
45    addr: Variant0NodeAddr,
46}
47
48impl Ticket for N0desTicket {
49    // KIND is the constant that's added to the front of a serialized ticket
50    // string. It should be a short, human readable string
51    const KIND: &'static str = "n0des";
52
53    fn to_bytes(&self) -> Vec<u8> {
54        let data = TicketWireFormat::Variant0(Variant0N0desTicket {
55            secret: self.secret.clone(),
56            addr: Variant0NodeAddr {
57                endpoint_id: self.remote.id,
58                info: Variant0AddrInfo {
59                    addrs: self.remote.addrs.clone(),
60                },
61            },
62        });
63        postcard::to_stdvec(&data).expect("postcard serialization failed")
64    }
65
66    fn from_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
67        let res: TicketWireFormat = postcard::from_bytes(bytes)?;
68        let TicketWireFormat::Variant0(Variant0N0desTicket { secret, addr }) = res;
69        Ok(Self {
70            secret,
71            remote: EndpointAddr {
72                id: addr.endpoint_id,
73                addrs: addr.info.addrs.clone(),
74            },
75        })
76    }
77}
78
79impl FromStr for N0desTicket {
80    type Err = ParseError;
81
82    fn from_str(s: &str) -> Result<Self, Self::Err> {
83        iroh_tickets::Ticket::deserialize(s)
84    }
85}
86
87impl N0desTicket {
88    /// Creates a new ticket.
89    pub fn new(secret: SecretKey, remote: impl Into<EndpointAddr>) -> Self {
90        Self {
91            secret,
92            remote: remote.into(),
93        }
94    }
95
96    /// The [`EndpointAddr`] of the provider for this ticket.
97    pub fn addr(&self) -> &EndpointAddr {
98        &self.remote
99    }
100}