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