1use std::str::FromStr;
4
5use serde::{Deserialize, Serialize};
6
7use super::{Variant0AddrInfo, Variant0NodeAddr};
8use crate::{
9 node_addr::NodeAddr,
10 ticket::{self, Ticket},
11};
12
13#[derive(Debug, Clone, PartialEq, Eq, derive_more::Display)]
31#[display("{}", Ticket::serialize(self))]
32pub struct NodeTicket {
33 node: NodeAddr,
34}
35
36#[derive(Serialize, Deserialize)]
38enum TicketWireFormat {
39 Variant0(Variant0NodeTicket),
40}
41
42#[derive(Serialize, Deserialize)]
44struct Variant0NodeTicket {
45 node: Variant0NodeAddr,
46}
47
48impl Ticket for NodeTicket {
49 const KIND: &'static str = "node";
50
51 fn to_bytes(&self) -> Vec<u8> {
52 let data = TicketWireFormat::Variant0(Variant0NodeTicket {
53 node: Variant0NodeAddr {
54 node_id: self.node.node_id,
55 info: Variant0AddrInfo {
56 relay_url: self.node.relay_url.clone(),
57 direct_addresses: self.node.direct_addresses.clone(),
58 },
59 },
60 });
61 postcard::to_stdvec(&data).expect("postcard serialization failed")
62 }
63
64 fn from_bytes(bytes: &[u8]) -> Result<Self, ticket::Error> {
65 let res: TicketWireFormat = postcard::from_bytes(bytes).map_err(ticket::Error::Postcard)?;
66 let TicketWireFormat::Variant0(Variant0NodeTicket { node }) = res;
67 Ok(Self {
68 node: NodeAddr {
69 node_id: node.node_id,
70 relay_url: node.info.relay_url,
71 direct_addresses: node.info.direct_addresses,
72 },
73 })
74 }
75}
76
77impl FromStr for NodeTicket {
78 type Err = ticket::Error;
79
80 fn from_str(s: &str) -> Result<Self, Self::Err> {
81 ticket::Ticket::deserialize(s)
82 }
83}
84
85impl NodeTicket {
86 pub fn new(node: NodeAddr) -> Self {
88 Self { node }
89 }
90
91 pub fn node_addr(&self) -> &NodeAddr {
93 &self.node
94 }
95}
96
97impl From<NodeAddr> for NodeTicket {
98 fn from(addr: NodeAddr) -> Self {
100 Self { node: addr }
101 }
102}
103
104impl From<NodeTicket> for NodeAddr {
105 fn from(ticket: NodeTicket) -> Self {
107 ticket.node
108 }
109}
110
111impl Serialize for NodeTicket {
112 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
113 if serializer.is_human_readable() {
114 serializer.serialize_str(&self.to_string())
115 } else {
116 let NodeTicket { node } = self;
117 (node).serialize(serializer)
118 }
119 }
120}
121
122impl<'de> Deserialize<'de> for NodeTicket {
123 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
124 if deserializer.is_human_readable() {
125 let s = String::deserialize(deserializer)?;
126 Self::from_str(&s).map_err(serde::de::Error::custom)
127 } else {
128 let peer = Deserialize::deserialize(deserializer)?;
129 Ok(Self::new(peer))
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use std::net::{Ipv4Addr, SocketAddr};
137
138 use data_encoding::HEXLOWER;
139
140 use super::*;
141 use crate::key::{PublicKey, SecretKey};
142
143 fn make_ticket() -> NodeTicket {
144 let peer = SecretKey::generate(&mut rand::thread_rng()).public();
145 let addr = SocketAddr::from((Ipv4Addr::LOCALHOST, 1234));
146 let relay_url = None;
147 NodeTicket {
148 node: NodeAddr::from_parts(peer, relay_url, [addr]),
149 }
150 }
151
152 #[test]
153 fn test_ticket_postcard() {
154 let ticket = make_ticket();
155 let bytes = postcard::to_stdvec(&ticket).unwrap();
156 let ticket2: NodeTicket = postcard::from_bytes(&bytes).unwrap();
157 assert_eq!(ticket2, ticket);
158 }
159
160 #[test]
161 fn test_ticket_json() {
162 let ticket = make_ticket();
163 let json = serde_json::to_string(&ticket).unwrap();
164 let ticket2: NodeTicket = serde_json::from_str(&json).unwrap();
165 assert_eq!(ticket2, ticket);
166 }
167
168 #[test]
169 fn test_ticket_base32() {
170 let node_id =
171 PublicKey::from_str("ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6")
172 .unwrap();
173
174 let ticket = NodeTicket {
175 node: NodeAddr::from_parts(
176 node_id,
177 Some("http://derp.me./".parse().unwrap()),
178 ["127.0.0.1:1024".parse().unwrap()],
179 ),
180 };
181 let base32 = data_encoding::BASE32_NOPAD
182 .decode(
183 ticket
184 .to_string()
185 .strip_prefix("node")
186 .unwrap()
187 .to_ascii_uppercase()
188 .as_bytes(),
189 )
190 .unwrap();
191 let expected = [
192 "00",
194 "ae58ff8833241ac82d6ff7611046ed67b5072d142c588d0063e942d9a75502b6",
196 "01",
198 "10",
200 "687474703a2f2f646572702e6d652e2f",
201 "01",
203 "00",
205 "7f0000018008",
207 ];
208 let expected = HEXLOWER.decode(expected.concat().as_bytes()).unwrap();
209 assert_eq!(base32, expected);
210 }
211}