1use alloc::boxed::Box;
2
3use umsh_core::{MicSize, PublicKey};
4use umsh_mac::SendOptions;
5
6pub const PING_MIC_SIZE: MicSize = MicSize::Mic8;
18
19use crate::node::{LocalNode, NodeError, Subscription, SubscriptionHandle};
20use crate::receive::ReceivedPacketRef;
21use crate::ticket::SendProgressTicket;
22use crate::transport::Transport;
23
24#[derive(Clone)]
29pub struct PeerConnection<T: Transport> {
30 transport: T,
31 peer: PublicKey,
32}
33
34impl<T: Transport> PeerConnection<T> {
35 pub(crate) fn new(transport: T, peer: PublicKey) -> Self {
37 Self { transport, peer }
38 }
39
40 pub fn peer(&self) -> &PublicKey {
42 &self.peer
43 }
44
45 pub async fn send(
47 &self,
48 payload: &[u8],
49 options: &SendOptions,
50 ) -> Result<SendProgressTicket, T::Error> {
51 self.transport.send(&self.peer, payload, options).await
52 }
53}
54
55impl<M, T> PeerConnection<T>
61where
62 M: crate::mac::MacBackend,
63 T: Transport<Error = NodeError<M>> + crate::transport::NodeAccess<Backend = M>,
64{
65 fn add_receive_handler<F>(&self, handler: F) -> SubscriptionHandle
66 where
67 F: FnMut(&ReceivedPacketRef<'_>) -> bool + 'static,
68 {
69 self.transport
70 .local_node()
71 .state()
72 .borrow_mut()
73 .peer_subscriptions_mut(self.peer)
74 .receive_handlers
75 .insert(Box::new(handler))
76 }
77
78 pub fn on_receive<F>(&self, handler: F) -> Subscription
79 where
80 F: FnMut(&ReceivedPacketRef<'_>) -> bool + 'static,
81 {
82 let handle = self.add_receive_handler(handler);
83 let state = self.transport.local_node().state().clone();
84 let peer = self.peer;
85 Subscription::new(move || {
86 let mut state = state.borrow_mut();
87 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
88 return false;
89 };
90 entry.receive_handlers.remove(handle)
91 })
92 }
93
94 fn add_ack_received_handler<F>(&self, handler: F) -> SubscriptionHandle
95 where
96 F: FnMut(crate::SendToken) + 'static,
97 {
98 self.transport
99 .local_node()
100 .state()
101 .borrow_mut()
102 .peer_subscriptions_mut(self.peer)
103 .ack_received_handlers
104 .insert(Box::new(handler))
105 }
106
107 pub fn on_ack_received<F>(&self, handler: F) -> Subscription
108 where
109 F: FnMut(crate::SendToken) + 'static,
110 {
111 let handle = self.add_ack_received_handler(handler);
112 let state = self.transport.local_node().state().clone();
113 let peer = self.peer;
114 Subscription::new(move || {
115 let mut state = state.borrow_mut();
116 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
117 return false;
118 };
119 entry.ack_received_handlers.remove(handle)
120 })
121 }
122
123 fn add_ack_timeout_handler<F>(&self, handler: F) -> SubscriptionHandle
124 where
125 F: FnMut(crate::SendToken) + 'static,
126 {
127 self.transport
128 .local_node()
129 .state()
130 .borrow_mut()
131 .peer_subscriptions_mut(self.peer)
132 .ack_timeout_handlers
133 .insert(Box::new(handler))
134 }
135
136 pub fn on_ack_timeout<F>(&self, handler: F) -> Subscription
137 where
138 F: FnMut(crate::SendToken) + 'static,
139 {
140 let handle = self.add_ack_timeout_handler(handler);
141 let state = self.transport.local_node().state().clone();
142 let peer = self.peer;
143 Subscription::new(move || {
144 let mut state = state.borrow_mut();
145 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
146 return false;
147 };
148 entry.ack_timeout_handlers.remove(handle)
149 })
150 }
151
152 pub fn on_pfs_established<F>(&self, handler: F) -> Subscription
153 where
154 F: FnMut() + 'static,
155 {
156 let handle = self
157 .transport
158 .local_node()
159 .state()
160 .borrow_mut()
161 .peer_subscriptions_mut(self.peer)
162 .pfs_established_handlers
163 .insert(Box::new(handler));
164 let state = self.transport.local_node().state().clone();
165 let peer = self.peer;
166 Subscription::new(move || {
167 let mut state = state.borrow_mut();
168 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
169 return false;
170 };
171 entry.pfs_established_handlers.remove(handle)
172 })
173 }
174
175 pub fn on_pfs_ended<F>(&self, handler: F) -> Subscription
176 where
177 F: FnMut() + 'static,
178 {
179 let handle = self
180 .transport
181 .local_node()
182 .state()
183 .borrow_mut()
184 .peer_subscriptions_mut(self.peer)
185 .pfs_ended_handlers
186 .insert(Box::new(handler));
187 let state = self.transport.local_node().state().clone();
188 let peer = self.peer;
189 Subscription::new(move || {
190 let mut state = state.borrow_mut();
191 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
192 return false;
193 };
194 entry.pfs_ended_handlers.remove(handle)
195 })
196 }
197
198 pub fn on_pong<F>(&self, handler: F) -> Subscription
199 where
200 F: FnMut(u64) + 'static,
201 {
202 let handle = self
203 .transport
204 .local_node()
205 .state()
206 .borrow_mut()
207 .peer_subscriptions_mut(self.peer)
208 .pong_handlers
209 .insert(Box::new(handler));
210 let state = self.transport.local_node().state().clone();
211 let peer = self.peer;
212 Subscription::new(move || {
213 let mut state = state.borrow_mut();
214 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
215 return false;
216 };
217 entry.pong_handlers.remove(handle)
218 })
219 }
220
221 pub fn on_ping_timeout<F>(&self, handler: F) -> Subscription
222 where
223 F: FnMut() + 'static,
224 {
225 let handle = self
226 .transport
227 .local_node()
228 .state()
229 .borrow_mut()
230 .peer_subscriptions_mut(self.peer)
231 .ping_timeout_handlers
232 .insert(Box::new(handler));
233 let state = self.transport.local_node().state().clone();
234 let peer = self.peer;
235 Subscription::new(move || {
236 let mut state = state.borrow_mut();
237 let Some(entry) = state.find_peer_subscriptions_mut(peer) else {
238 return false;
239 };
240 entry.ping_timeout_handlers.remove(handle)
241 })
242 }
243
244 pub async fn ping(
263 &self,
264 extra_bytes: usize,
265 options: &SendOptions,
266 timeout_ms: u64,
267 ) -> Result<crate::ticket::SendProgressTicket, NodeError<M>> {
268 let mut nonce_bytes = [0u8; 2];
270 self.transport
271 .local_node()
272 .fill_random(&mut nonce_bytes)
273 .await;
274 let nonce = u16::from_be_bytes(nonce_bytes);
275
276 let total = 2 + extra_bytes;
278 let mut data = alloc::vec![0xA5u8; total];
279 data[0] = nonce_bytes[0];
280 data[1] = nonce_bytes[1];
281
282 let cmd = crate::mac_command::MacCommand::EchoRequest { data: &data };
287 let mut buf = alloc::vec![0u8; total + 2];
288 buf[0] = umsh_core::PayloadType::MacCommand as u8;
289 let n = crate::mac_command::encode(&cmd, &mut buf[1..])?;
290 let n = n + 1;
291
292 let sent_at_ms = self.transport.local_node().now_ms().await;
294 self.transport.local_node().record_ping(
295 nonce,
296 self.peer,
297 sent_at_ms,
298 sent_at_ms + timeout_ms,
299 );
300
301 let opts = options.clone().with_ack_requested(false);
306 self.send(&buf[..n], &opts).await
307 }
308
309 pub async fn request_identity(
319 &self,
320 options: &SendOptions,
321 ) -> Result<SendProgressTicket, NodeError<M>> {
322 let mut nonce_bytes = [0u8; 4];
323 self.transport
324 .local_node()
325 .fill_random(&mut nonce_bytes)
326 .await;
327 let nonce = u32::from_be_bytes(nonce_bytes);
328
329 let opts_block = crate::mac_command::IdentityRequestBuilder::new()
330 .nonce(nonce)?
331 .build();
332 let cmd = crate::mac_command::MacCommand::IdentityRequest {
333 options: &opts_block,
334 };
335 let mut buf = [0u8; 128];
336 buf[0] = umsh_core::PayloadType::MacCommand as u8;
337 let n = crate::mac_command::encode(&cmd, &mut buf[1..])? + 1;
338
339 self.send(&buf[..n], options).await
340 }
341
342 pub async fn request_peer_repeaters(
352 &self,
353 nonce: u16,
354 cursor: Option<&[u8]>,
355 options: &SendOptions,
356 ) -> Result<SendProgressTicket, NodeError<M>> {
357 let mut builder = crate::mac_command::PeerRepeatersRequestBuilder::new().nonce(nonce)?;
358 if let Some(cursor) = cursor {
359 builder = builder.cursor(cursor)?;
360 }
361 let opts_block = builder.build();
362 let cmd = crate::mac_command::MacCommand::PeerRepeatersRequest {
363 options: &opts_block,
364 };
365 let mut buf = [0u8; 128];
366 buf[0] = umsh_core::PayloadType::MacCommand as u8;
367 let n = crate::mac_command::encode(&cmd, &mut buf[1..])? + 1;
368
369 self.send(&buf[..n], options).await
370 }
371
372 pub async fn route(&self) -> Option<umsh_mac::CachedRoute> {
374 self.transport.local_node().peer_route(&self.peer).await
375 }
376
377 pub async fn clear_route(&self) -> bool {
379 self.transport
380 .local_node()
381 .clear_peer_route(&self.peer)
382 .await
383 }
384
385 pub async fn restore_route(&self, route: umsh_mac::CachedRoute) -> bool {
388 self.transport
389 .local_node()
390 .restore_peer_route(&self.peer, route)
391 .await
392 }
393}
394
395impl<M: crate::mac::MacBackend> PeerConnection<LocalNode<M>> {
399 #[cfg(feature = "software-crypto")]
400 pub async fn request_pfs(
401 &self,
402 duration_minutes: u16,
403 options: &SendOptions,
404 ) -> Result<SendProgressTicket, NodeError<M>> {
405 self.transport
406 .request_pfs(&self.peer, duration_minutes, options)
407 .await
408 }
409
410 #[cfg(feature = "software-crypto")]
411 pub async fn end_pfs(&self, options: &SendOptions) -> Result<(), NodeError<M>> {
412 self.transport.end_pfs(&self.peer, options).await
413 }
414
415 #[cfg(feature = "software-crypto")]
416 pub async fn pfs_status(&self) -> Result<crate::node::PfsStatus, NodeError<M>> {
417 self.transport.pfs_status(&self.peer).await
418 }
419}