1use std::fmt::{self, Display};
20use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
21use std::str::FromStr;
22
23use anyhow::{Result, anyhow};
24use serde::{Deserialize, Serialize};
25
26use four_word_networking::FourWordAdaptiveEncoder;
27
28#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
30pub struct NetworkAddress {
31 pub socket_addr: SocketAddr,
33 pub four_words: Option<String>,
35}
36
37impl NetworkAddress {
38 #[must_use]
40 pub fn new(socket_addr: SocketAddr) -> Self {
41 let four_words = Self::encode_four_words(&socket_addr);
42 Self {
43 socket_addr,
44 four_words,
45 }
46 }
47
48 #[must_use]
50 pub fn from_ip_port(ip: IpAddr, port: u16) -> Self {
51 let socket_addr = SocketAddr::new(ip, port);
52 Self::new(socket_addr)
53 }
54
55 #[must_use]
57 pub fn from_ipv4(ip: Ipv4Addr, port: u16) -> Self {
58 Self::from_ip_port(IpAddr::V4(ip), port)
59 }
60
61 #[must_use]
63 pub fn from_ipv6(ip: Ipv6Addr, port: u16) -> Self {
64 Self::from_ip_port(IpAddr::V6(ip), port)
65 }
66
67 #[must_use]
69 pub fn ip(&self) -> IpAddr {
70 self.socket_addr.ip()
71 }
72
73 pub fn port(&self) -> u16 {
75 self.socket_addr.port()
76 }
77
78 pub fn socket_addr(&self) -> SocketAddr {
80 self.socket_addr
81 }
82
83 pub fn four_words(&self) -> Option<&str> {
85 self.four_words.as_deref()
86 }
87
88 pub fn regenerate_four_words(&mut self) {
90 self.four_words = Self::encode_four_words(&self.socket_addr);
91 }
92
93 fn encode_four_words(addr: &SocketAddr) -> Option<String> {
95 match FourWordAdaptiveEncoder::new()
96 .and_then(|enc| enc.encode(&addr.to_string()))
97 {
98 Ok(s) => Some(s.replace(' ', "-")),
99 Err(e) => {
100 log::warn!("Failed to encode address {addr}: {e}");
101 None
102 }
103 }
104 }
105
106 pub fn from_four_words(words: &str) -> Result<Self> {
108 let enc = FourWordAdaptiveEncoder::new()?;
109 let decoded = enc.decode(words)?; let socket_addr: SocketAddr = decoded.parse()?; Ok(Self::new(socket_addr))
112 }
113
114 pub fn is_ipv4(&self) -> bool {
116 self.socket_addr.is_ipv4()
117 }
118
119 pub fn is_ipv6(&self) -> bool {
121 self.socket_addr.is_ipv6()
122 }
123
124 pub fn is_loopback(&self) -> bool {
126 self.socket_addr.ip().is_loopback()
127 }
128
129 pub fn is_private(&self) -> bool {
131 match self.socket_addr.ip() {
132 IpAddr::V4(ip) => ip.is_private(),
133 IpAddr::V6(ip) => {
134 let octets = ip.octets();
136 (octets[0] & 0xfe) == 0xfc
137 }
138 }
139 }
140}
141
142impl Display for NetworkAddress {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 if let Some(ref words) = self.four_words {
145 write!(f, "{} ({})", self.socket_addr, words)
146 } else {
147 write!(f, "{}", self.socket_addr)
148 }
149 }
150}
151
152impl FromStr for NetworkAddress {
153 type Err = anyhow::Error;
154
155 fn from_str(s: &str) -> Result<Self> {
156 if let Ok(socket_addr) = SocketAddr::from_str(s) {
158 return Ok(Self::new(socket_addr));
159 }
160
161 if let Ok(addr) = Self::from_four_words(s) {
163 return Ok(addr);
164 }
165
166 Err(anyhow!("Invalid address format: {}", s))
167 }
168}
169
170impl From<SocketAddr> for NetworkAddress {
171 fn from(socket_addr: SocketAddr) -> Self {
172 Self::new(socket_addr)
173 }
174}
175
176impl From<&SocketAddr> for NetworkAddress {
177 fn from(socket_addr: &SocketAddr) -> Self {
178 Self::new(*socket_addr)
179 }
180}
181
182impl From<NetworkAddress> for SocketAddr {
183 fn from(addr: NetworkAddress) -> Self {
184 addr.socket_addr
185 }
186}
187
188impl From<&NetworkAddress> for SocketAddr {
189 fn from(addr: &NetworkAddress) -> Self {
190 addr.socket_addr
191 }
192}
193
194#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
196pub struct AddressBook {
197 pub addresses: Vec<NetworkAddress>,
199 pub last_known_good: Option<NetworkAddress>,
201}
202
203impl AddressBook {
204 pub fn new() -> Self {
206 Self {
207 addresses: Vec::new(),
208 last_known_good: None,
209 }
210 }
211
212 pub fn with_address(address: NetworkAddress) -> Self {
214 Self {
215 addresses: vec![address.clone()],
216 last_known_good: Some(address),
217 }
218 }
219
220 pub fn add_address(&mut self, address: NetworkAddress) {
222 if !self.addresses.contains(&address) {
223 self.addresses.push(address);
224 }
225 }
226
227 pub fn remove_address(&mut self, address: &NetworkAddress) {
229 self.addresses.retain(|a| a != address);
230 if self.last_known_good.as_ref() == Some(address) {
231 self.last_known_good = self.addresses.first().cloned();
232 }
233 }
234
235 pub fn update_last_known_good(&mut self, address: NetworkAddress) {
237 if self.addresses.contains(&address) {
238 self.last_known_good = Some(address);
239 }
240 }
241
242 pub fn best_address(&self) -> Option<&NetworkAddress> {
244 self.last_known_good
245 .as_ref()
246 .or_else(|| self.addresses.first())
247 }
248
249 pub fn addresses(&self) -> &[NetworkAddress] {
251 &self.addresses
252 }
253
254 pub fn is_empty(&self) -> bool {
256 self.addresses.is_empty()
257 }
258
259 pub fn len(&self) -> usize {
261 self.addresses.len()
262 }
263}
264
265impl Default for AddressBook {
266 fn default() -> Self {
267 Self::new()
268 }
269}
270
271impl Display for AddressBook {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 if self.addresses.is_empty() {
274 write!(f, "Empty address book")
275 } else {
276 write!(
277 f,
278 "Addresses: [{}]",
279 self.addresses
280 .iter()
281 .map(|a| a.to_string())
282 .collect::<Vec<_>>()
283 .join(", ")
284 )
285 }
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use std::net::{Ipv4Addr, Ipv6Addr};
293
294 #[test]
295 fn test_network_address_creation() {
296 let addr = NetworkAddress::from_ipv4(Ipv4Addr::new(127, 0, 0, 1), 8080);
297 assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
298 assert_eq!(addr.port(), 8080);
299 assert!(addr.is_ipv4());
300 assert!(addr.is_loopback());
301 }
302
303 #[test]
304 fn test_network_address_from_string() {
305 let addr = "127.0.0.1:8080".parse::<NetworkAddress>().unwrap();
306 assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
307 assert_eq!(addr.port(), 8080);
308 }
309
310 #[test]
311 fn test_network_address_display() {
312 let addr = NetworkAddress::from_ipv4(Ipv4Addr::new(192, 168, 1, 1), 9000);
313 let display = addr.to_string();
314 assert!(display.contains("192.168.1.1:9000"));
315 }
316
317 #[test]
318 fn test_address_book() {
319 let mut book = AddressBook::new();
320 let addr1 = NetworkAddress::from_ipv4(Ipv4Addr::new(192, 168, 1, 1), 9000);
321 let addr2 = NetworkAddress::from_ipv4(Ipv4Addr::new(192, 168, 1, 2), 9001);
322
323 book.add_address(addr1.clone());
324 book.add_address(addr2.clone());
325
326 assert_eq!(book.len(), 2);
327 assert_eq!(book.best_address(), Some(&addr1));
328
329 book.update_last_known_good(addr2.clone());
330 assert_eq!(book.best_address(), Some(&addr2));
331 }
332
333 #[test]
334 fn test_private_address_detection() {
335 let private_addr = NetworkAddress::from_ipv4(Ipv4Addr::new(192, 168, 1, 1), 9000);
336 assert!(private_addr.is_private());
337
338 let public_addr = NetworkAddress::from_ipv4(Ipv4Addr::new(8, 8, 8, 8), 53);
339 assert!(!public_addr.is_private());
340 }
341
342 #[test]
343 fn test_ipv6_address() {
344 let addr = NetworkAddress::from_ipv6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080);
345 assert!(addr.is_ipv6());
346 assert!(addr.is_loopback());
347 }
348}