dynamo_runtime/utils/
ip_resolver.rs1use crate::pipeline::network::tcp::server::{DefaultIpResolver, IpResolver};
7use local_ip_address::Error;
8use std::net::{IpAddr, Ipv4Addr};
9
10const FALLBACK: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
11
12pub fn local_ip_for_advertise() -> String {
17 resolve(DefaultIpResolver)
18}
19
20pub fn tcp_rpc_host_from_env() -> String {
22 std::env::var("DYN_TCP_RPC_HOST").unwrap_or_else(|_| local_ip_for_advertise())
23}
24
25fn resolve<R: IpResolver>(resolver: R) -> String {
26 let ip = resolver
27 .local_ip()
28 .or_else(|err| match err {
29 Error::LocalIpAddressNotFound => resolver.local_ipv6(),
30 _ => Err(err),
31 })
32 .unwrap_or(FALLBACK);
33
34 match ip {
35 IpAddr::V6(_) => format!("[{ip}]"),
36 IpAddr::V4(_) => ip.to_string(),
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 struct MockIpResolver {
45 v4: Result<IpAddr, Error>,
46 v6: Result<IpAddr, Error>,
47 }
48
49 impl IpResolver for MockIpResolver {
50 fn local_ip(&self) -> Result<IpAddr, Error> {
51 self.v4
52 .as_ref()
53 .copied()
54 .map_err(|_| Error::LocalIpAddressNotFound)
55 }
56
57 fn local_ipv6(&self) -> Result<IpAddr, Error> {
58 self.v6
59 .as_ref()
60 .copied()
61 .map_err(|_| Error::LocalIpAddressNotFound)
62 }
63 }
64
65 #[test]
66 fn ipv4_returned_unbracketed() {
67 let r = MockIpResolver {
68 v4: Ok(IpAddr::from([192, 168, 1, 100])),
69 v6: Err(Error::LocalIpAddressNotFound),
70 };
71 assert_eq!(resolve(r), "192.168.1.100");
72 }
73
74 #[test]
75 fn ipv6_fallback_is_bracketed() {
76 let r = MockIpResolver {
77 v4: Err(Error::LocalIpAddressNotFound),
78 v6: Ok(IpAddr::from([0x2001, 0xdb8, 0, 0, 0, 0, 0, 1])),
79 };
80 assert_eq!(resolve(r), "[2001:db8::1]");
81 }
82
83 #[test]
84 fn both_fail_uses_localhost() {
85 let r = MockIpResolver {
86 v4: Err(Error::LocalIpAddressNotFound),
87 v6: Err(Error::LocalIpAddressNotFound),
88 };
89 assert_eq!(resolve(r), "127.0.0.1");
90 }
91}