lnp/
addr.rs

1// LNP/BP Core Library implementing LNPBP specifications & standards
2// Written in 2019 by
3//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the MIT License
11// along with this software.
12// If not, see <https://opensource.org/licenses/MIT>.
13
14use std::fmt::{self, Display, Formatter};
15use std::str::FromStr;
16
17use internet2::addr::{
18    AddrParseError, NodeAddr, NodeAddrParseError, PartialNodeAddr,
19};
20#[cfg(feature = "bifrost")]
21use p2p::bifrost::LNP2P_BIFROST_PORT;
22#[cfg(feature = "bolt")]
23use p2p::bolt::LNP2P_BOLT_PORT;
24use p2p::Protocol;
25
26/// LNP node address containing both node address and the used protocol.
27/// When parsed from string or displayed, it may omit port information and use
28/// the protocol default port.
29#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Debug)]
30#[derive(NetworkEncode, NetworkDecode)]
31pub struct LnpAddr {
32    /// Protocol used for connection.
33    pub protocol: Protocol,
34
35    /// Remote peer address for connecting to.
36    pub node_addr: NodeAddr,
37}
38
39impl LnpAddr {
40    #[cfg(feature = "bolt")]
41    /// Construct BOLT-compatible node address.
42    pub fn bolt(addr: PartialNodeAddr) -> LnpAddr {
43        LnpAddr {
44            protocol: Protocol::Bolt,
45            node_addr: addr.node_addr(LNP2P_BOLT_PORT),
46        }
47    }
48
49    #[cfg(feature = "bifrost")]
50    /// Construct Bifrost-compatible node address.
51    pub fn bifrost(addr: PartialNodeAddr) -> LnpAddr {
52        LnpAddr {
53            protocol: Protocol::Bifrost,
54            node_addr: addr.node_addr(LNP2P_BIFROST_PORT),
55        }
56    }
57
58    /// Returns used port address.
59    pub fn port(self) -> u16 {
60        self.node_addr
61            .addr
62            .port()
63            .expect("port information always present in NodeAddr")
64    }
65}
66
67impl Display for LnpAddr {
68    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
69        write!(
70            f,
71            "{}://{}@{}",
72            self.protocol,
73            self.node_addr.id,
74            self.node_addr.addr.address()
75        )?;
76        if self.protocol.default_port() != self.port() {
77            write!(f, ":{}", self.port())?;
78        }
79        Ok(())
80    }
81}
82
83impl FromStr for LnpAddr {
84    type Err = NodeAddrParseError;
85
86    fn from_str(s: &str) -> Result<Self, Self::Err> {
87        let mut split = s.split("://");
88        match (
89            split.next().map(str::to_lowercase).as_deref(),
90            split.next(),
91            split.next(),
92        ) {
93            #[cfg(feature = "bolt")]
94            (Some("bolt"), Some(addr), None) => {
95                PartialNodeAddr::from_str(addr).map(LnpAddr::bolt)
96            }
97            #[cfg(feature = "bifrost")]
98            (Some("bifrost"), Some(addr), None) => {
99                PartialNodeAddr::from_str(addr).map(LnpAddr::bifrost)
100            }
101            (Some(unknown), ..) => {
102                Err(AddrParseError::UnknownProtocolError(unknown.to_owned())
103                    .into())
104            }
105            _ => Err(AddrParseError::WrongAddrFormat(s.to_owned()).into()),
106        }
107    }
108}