alpine_protocol_sdk/
discovery.rs1use std::{
2 fmt, io,
3 net::{SocketAddr, UdpSocket},
4 time::Duration,
5};
6
7use alpine::messages::{DiscoveryReply, DiscoveryRequest};
8use rand::{rngs::OsRng, RngCore};
9use serde_cbor;
10
11pub struct DiscoveryClientOptions {
13 pub remote_addr: SocketAddr,
14 pub local_addr: SocketAddr,
15 pub timeout: Duration,
16}
17
18impl DiscoveryClientOptions {
19 pub fn new(remote_addr: SocketAddr, local_addr: SocketAddr, timeout: Duration) -> Self {
21 Self {
22 remote_addr,
23 local_addr,
24 timeout,
25 }
26 }
27}
28
29#[derive(Debug)]
31pub enum DiscoveryError {
32 Io(io::Error),
33 Decode(serde_cbor::Error),
34 Timeout,
35}
36
37impl fmt::Display for DiscoveryError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 DiscoveryError::Io(err) => write!(f, "io error: {}", err),
41 DiscoveryError::Decode(err) => write!(f, "cbors serialization error: {}", err),
42 DiscoveryError::Timeout => write!(f, "discovery timed out"),
43 }
44 }
45}
46
47impl std::error::Error for DiscoveryError {}
48
49impl From<io::Error> for DiscoveryError {
50 fn from(err: io::Error) -> Self {
51 match err.kind() {
52 io::ErrorKind::TimedOut | io::ErrorKind::WouldBlock => DiscoveryError::Timeout,
53 _ => DiscoveryError::Io(err),
54 }
55 }
56}
57
58impl From<serde_cbor::Error> for DiscoveryError {
59 fn from(err: serde_cbor::Error) -> Self {
60 DiscoveryError::Decode(err)
61 }
62}
63
64pub struct DiscoveryOutcome {
66 pub reply: DiscoveryReply,
67 pub peer: SocketAddr,
68}
69
70pub struct DiscoveryClient {
72 socket: UdpSocket,
73 remote_addr: SocketAddr,
74}
75
76impl DiscoveryClient {
77 pub fn new(options: DiscoveryClientOptions) -> Result<Self, DiscoveryError> {
79 let socket = UdpSocket::bind(options.local_addr)?;
80 socket.set_read_timeout(Some(options.timeout))?;
81 Ok(Self {
82 socket,
83 remote_addr: options.remote_addr,
84 })
85 }
86
87 pub fn discover(&self, requested: &[String]) -> Result<DiscoveryOutcome, DiscoveryError> {
89 let mut nonce = vec![0u8; 32];
90 OsRng.fill_bytes(&mut nonce);
91 let request = DiscoveryRequest::new(requested.to_vec(), nonce.clone());
92 let payload = serde_cbor::to_vec(&request)?;
93 self.socket.send_to(&payload, self.remote_addr)?;
94
95 let mut buf = vec![0u8; 2048];
96 let (len, peer) = self.socket.recv_from(&mut buf)?;
97 let reply: DiscoveryReply = serde_cbor::from_slice(&buf[..len])?;
98 Ok(DiscoveryOutcome { reply, peer })
99 }
100}