use local_ip_address::{local_ip, local_ipv6};
use std::net::IpAddr;
pub(crate) fn format_socket_addr(ip: IpAddr, port: u16) -> String {
match ip {
IpAddr::V4(v4) => format!("{v4}:{port}"),
IpAddr::V6(v6) => format!("[{v6}]:{port}"),
}
}
pub(crate) fn format_url(scheme: &str, ip: IpAddr, port: u16) -> String {
format!("{}://{}", scheme, format_socket_addr(ip, port))
}
pub(crate) fn preferred_local_ip() -> Option<IpAddr> {
local_ip().ok().or_else(|| local_ipv6().ok())
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn format_socket_addr_brackets_ipv6() {
let test_cases = vec![
("127.0.0.1", 80, "127.0.0.1:80"),
("192.168.1.1", 8080, "192.168.1.1:8080"),
("::1", 80, "[::1]:80"),
("2001:db8::1", 8080, "[2001:db8::1]:8080"),
];
for (ip, port, expected) in test_cases {
assert_eq!(
format_socket_addr(IpAddr::from_str(ip).unwrap(), port),
expected
);
}
}
#[test]
fn format_url_brackets_ipv6() {
let test_cases = vec![
("http", "127.0.0.1", 80, "http://127.0.0.1:80"),
("https", "192.168.1.1", 443, "https://192.168.1.1:443"),
("http", "::1", 80, "http://[::1]:80"),
("https", "2001:db8::1", 443, "https://[2001:db8::1]:443"),
];
for (scheme, ip, port, expected) in test_cases {
assert_eq!(
format_url(scheme, IpAddr::from_str(ip).unwrap(), port),
expected
);
}
}
#[test]
fn preferred_local_ip_is_found() {
let ip = preferred_local_ip();
assert!(ip.is_some());
}
}