use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use internet2::addr::{
AddrParseError, NodeAddr, NodeAddrParseError, PartialNodeAddr,
};
#[cfg(feature = "bifrost")]
use p2p::bifrost::LNP2P_BIFROST_PORT;
#[cfg(feature = "bolt")]
use p2p::bolt::LNP2P_BOLT_PORT;
use p2p::Protocol;
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Debug)]
#[derive(NetworkEncode, NetworkDecode)]
pub struct LnpAddr {
pub protocol: Protocol,
pub node_addr: NodeAddr,
}
impl LnpAddr {
#[cfg(feature = "bolt")]
pub fn bolt(addr: PartialNodeAddr) -> LnpAddr {
LnpAddr {
protocol: Protocol::Bolt,
node_addr: addr.node_addr(LNP2P_BOLT_PORT),
}
}
#[cfg(feature = "bifrost")]
pub fn bifrost(addr: PartialNodeAddr) -> LnpAddr {
LnpAddr {
protocol: Protocol::Bifrost,
node_addr: addr.node_addr(LNP2P_BIFROST_PORT),
}
}
pub fn port(self) -> u16 {
self.node_addr
.addr
.port()
.expect("port information always present in NodeAddr")
}
}
impl Display for LnpAddr {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}://{}@{}",
self.protocol,
self.node_addr.id,
self.node_addr.addr.address()
)?;
if self.protocol.default_port() != self.port() {
write!(f, ":{}", self.port())?;
}
Ok(())
}
}
impl FromStr for LnpAddr {
type Err = NodeAddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut split = s.split("://");
match (
split.next().map(str::to_lowercase).as_deref(),
split.next(),
split.next(),
) {
#[cfg(feature = "bolt")]
(Some("bolt"), Some(addr), None) => {
PartialNodeAddr::from_str(addr).map(LnpAddr::bolt)
}
#[cfg(feature = "bifrost")]
(Some("bifrost"), Some(addr), None) => {
PartialNodeAddr::from_str(addr).map(LnpAddr::bifrost)
}
(Some(unknown), ..) => {
Err(AddrParseError::UnknownProtocolError(unknown.to_owned())
.into())
}
_ => Err(AddrParseError::WrongAddrFormat(s.to_owned()).into()),
}
}
}