1use crate::error::{ERR_IDENTITY_INVALID_ADDR, Error, check};
2use crate::ffi;
3use crate::types::{BASE58_ADDR_LEN, NodeId, URL_MAX_LEN};
4use std::ffi::CString;
5use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
6
7#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct Addr {
16 pub ip: [u8; 16],
18 pub node_id: NodeId,
20 pub port: u16,
22}
23
24impl Addr {
25 pub fn new_ipv4(ipv4: Ipv4Addr, node_id: NodeId, port: u16) -> Self {
27 let mut ip = [0u8; 16];
28 ip[10] = 0xff;
30 ip[11] = 0xff;
31 let octets = ipv4.octets();
32 ip[12..16].copy_from_slice(&octets);
33 Addr { ip, node_id, port }
34 }
35
36 pub fn new_ipv6(ipv6: Ipv6Addr, node_id: NodeId, port: u16) -> Self {
38 Addr {
39 ip: ipv6.octets(),
40 node_id,
41 port,
42 }
43 }
44
45 pub fn ip_addr(&self) -> IpAddr {
47 if self.ip[..10].iter().all(|&b| b == 0) && self.ip[10] == 0xff && self.ip[11] == 0xff {
49 let octets = [self.ip[12], self.ip[13], self.ip[14], self.ip[15]];
50 IpAddr::V4(Ipv4Addr::from(octets))
51 } else {
52 IpAddr::V6(Ipv6Addr::from(self.ip))
53 }
54 }
55
56 pub fn encode(&self) -> Result<String, Error> {
62 let ffi_addr = self.to_ffi();
63 let mut buf = vec![0u8; BASE58_ADDR_LEN + 2];
64 let n = unsafe { ffi::nwep_addr_encode(buf.as_mut_ptr().cast(), buf.len(), &ffi_addr) };
65 if n == 0 {
66 Err(Error::from_code(ERR_IDENTITY_INVALID_ADDR))
67 } else {
68 Ok(String::from_utf8_lossy(&buf[..n]).into_owned())
69 }
70 }
71
72 pub fn decode(encoded: &str) -> Result<Self, Error> {
78 let c = CString::new(encoded).map_err(|_| Error::from_code(ERR_IDENTITY_INVALID_ADDR))?;
79 let mut ffi_addr = ffi::nwep_addr {
80 ip: [0u8; 16],
81 nodeid: ffi::nwep_nodeid { data: [0u8; 32] },
82 port: 0,
83 };
84 check(unsafe { ffi::nwep_addr_decode(&mut ffi_addr, c.as_ptr()) })?;
85 Ok(Addr::from_ffi(&ffi_addr))
86 }
87
88 pub(crate) fn to_ffi(&self) -> ffi::nwep_addr {
89 ffi::nwep_addr {
90 ip: self.ip,
91 nodeid: ffi::nwep_nodeid {
92 data: self.node_id.0,
93 },
94 port: self.port,
95 }
96 }
97
98 pub(crate) fn from_ffi(a: &ffi::nwep_addr) -> Self {
99 Addr {
100 ip: a.ip,
101 node_id: NodeId(a.nodeid.data),
102 port: a.port,
103 }
104 }
105}
106
107#[derive(Clone, Debug, PartialEq, Eq)]
113pub struct Url {
114 pub addr: Addr,
116 pub path: String,
118}
119
120impl Url {
121 pub fn parse(s: &str) -> Result<Self, Error> {
127 let c = CString::new(s).map_err(|_| Error::from_code(ERR_IDENTITY_INVALID_ADDR))?;
128 let mut ffi_url = unsafe { std::mem::zeroed::<ffi::nwep_url>() };
129 check(unsafe { ffi::nwep_url_parse(&mut ffi_url, c.as_ptr()) })?;
130 let path = unsafe {
131 std::ffi::CStr::from_ptr(ffi_url.path.as_ptr())
132 .to_string_lossy()
133 .into_owned()
134 };
135 Ok(Url {
136 addr: Addr::from_ffi(&ffi_url.addr),
137 path,
138 })
139 }
140
141 pub fn format(&self) -> Result<String, Error> {
147 let ffi_url = self.to_ffi_url();
148 let mut buf = vec![0u8; URL_MAX_LEN];
149 let n = unsafe { ffi::nwep_url_format(buf.as_mut_ptr().cast(), buf.len(), &ffi_url) };
150 if n == 0 {
151 Err(Error::from_code(ERR_IDENTITY_INVALID_ADDR))
152 } else {
153 Ok(String::from_utf8_lossy(&buf[..n]).into_owned())
154 }
155 }
156
157 fn to_ffi_url(&self) -> ffi::nwep_url {
158 self.to_ffi()
159 }
160
161 pub(crate) fn to_ffi(&self) -> ffi::nwep_url {
162 let mut ffi_url = unsafe { std::mem::zeroed::<ffi::nwep_url>() };
163 ffi_url.addr = self.addr.to_ffi();
164 let path_bytes = self.path.as_bytes();
165 let len = path_bytes.len().min(255);
166 for (i, &b) in path_bytes[..len].iter().enumerate() {
168 ffi_url.path[i] = b as _;
169 }
170 ffi_url
171 }
172}
173
174impl std::fmt::Display for Url {
175 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self.format() {
177 Ok(s) => f.write_str(&s),
178 Err(_) => write!(f, "web://[invalid]:{}{}", self.addr.port, self.path),
179 }
180 }
181}