dynamo_runtime/utils/
ip_resolver.rs1use crate::pipeline::network::tcp::server::{DefaultIpResolver, IpResolver};
7use local_ip_address::Error;
8use std::net::IpAddr;
9
10fn resolve_local_ip_with_resolver<R: IpResolver>(resolver: R) -> IpAddr {
11 let resolved_ip = resolver.local_ip().or_else(|err| match err {
12 Error::LocalIpAddressNotFound => resolver.local_ipv6(),
13 _ => Err(err),
14 });
15
16 match resolved_ip {
17 Ok(addr) => addr,
18 Err(Error::LocalIpAddressNotFound) => IpAddr::from([127, 0, 0, 1]),
19 Err(_) => IpAddr::from([127, 0, 0, 1]), }
21}
22
23fn format_ip_for_url(addr: IpAddr) -> String {
24 match addr {
27 IpAddr::V6(_) => format!("[{}]", addr),
28 IpAddr::V4(_) => addr.to_string(),
29 }
30}
31
32pub fn get_local_ip_for_advertise_with_resolver<R: IpResolver>(resolver: R) -> String {
45 format_ip_for_url(resolve_local_ip_with_resolver(resolver))
46}
47
48pub fn get_local_ip_for_advertise() -> String {
50 get_local_ip_for_advertise_with_resolver(DefaultIpResolver)
51}
52
53pub fn get_http_rpc_host_with_resolver<R: IpResolver>(resolver: R) -> String {
55 get_local_ip_for_advertise_with_resolver(resolver)
56}
57
58pub fn get_http_rpc_host() -> String {
66 get_http_rpc_host_with_resolver(DefaultIpResolver)
67}
68
69pub fn get_http_rpc_host_from_env() -> String {
77 std::env::var("DYN_HTTP_RPC_HOST").unwrap_or_else(|_| get_http_rpc_host())
78}
79
80pub fn get_tcp_rpc_host_from_env() -> String {
88 std::env::var("DYN_TCP_RPC_HOST").unwrap_or_else(|_| get_http_rpc_host())
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use local_ip_address::Error;
95
96 struct MockIpResolver {
98 ipv4_result: Result<IpAddr, Error>,
99 ipv6_result: Result<IpAddr, Error>,
100 }
101
102 impl IpResolver for MockIpResolver {
103 fn local_ip(&self) -> Result<IpAddr, Error> {
104 match &self.ipv4_result {
105 Ok(addr) => Ok(*addr),
106 Err(Error::LocalIpAddressNotFound) => Err(Error::LocalIpAddressNotFound),
107 Err(_) => Err(Error::LocalIpAddressNotFound), }
109 }
110
111 fn local_ipv6(&self) -> Result<IpAddr, Error> {
112 match &self.ipv6_result {
113 Ok(addr) => Ok(*addr),
114 Err(Error::LocalIpAddressNotFound) => Err(Error::LocalIpAddressNotFound),
115 Err(_) => Err(Error::LocalIpAddressNotFound), }
117 }
118 }
119
120 #[test]
121 fn test_get_http_rpc_host_with_successful_ipv4() {
122 let resolver = MockIpResolver {
123 ipv4_result: Ok(IpAddr::from([192, 168, 1, 100])),
124 ipv6_result: Ok(IpAddr::from([0, 0, 0, 0, 0, 0, 0, 1])),
125 };
126
127 let result = get_http_rpc_host_with_resolver(resolver);
128 assert_eq!(result, "192.168.1.100");
129 }
130
131 #[test]
132 fn test_get_http_rpc_host_with_ipv4_fail_ipv6_success() {
133 let resolver = MockIpResolver {
134 ipv4_result: Err(Error::LocalIpAddressNotFound),
135 ipv6_result: Ok(IpAddr::from([0x2001, 0xdb8, 0, 0, 0, 0, 0, 1])),
136 };
137
138 let result = get_http_rpc_host_with_resolver(resolver);
139 assert_eq!(result, "[2001:db8::1]");
141 }
142
143 #[test]
144 fn test_get_http_rpc_host_with_both_fail() {
145 let resolver = MockIpResolver {
146 ipv4_result: Err(Error::LocalIpAddressNotFound),
147 ipv6_result: Err(Error::LocalIpAddressNotFound),
148 };
149
150 let result = get_http_rpc_host_with_resolver(resolver);
151 assert_eq!(result, "127.0.0.1");
152 }
153
154 #[test]
155 fn test_get_http_rpc_host_from_env_with_env_var() {
156 unsafe {
158 std::env::set_var("DYN_HTTP_RPC_HOST", "10.0.0.1");
159 }
160
161 let result = get_http_rpc_host_from_env();
162 assert_eq!(result, "10.0.0.1");
163
164 unsafe {
166 std::env::remove_var("DYN_HTTP_RPC_HOST");
167 }
168 }
169
170 #[test]
171 fn test_get_http_rpc_host_from_env_without_env_var() {
172 let result = get_http_rpc_host_from_env();
176 assert!(!result.is_empty());
178
179 let ip_str = result.trim_start_matches('[').trim_end_matches(']');
181 let _: IpAddr = ip_str.parse().expect("Should be a valid IP address");
182 }
183
184 #[test]
185 fn test_ipv6_address_is_bracketed() {
186 let resolver = MockIpResolver {
187 ipv4_result: Err(Error::LocalIpAddressNotFound),
188 ipv6_result: Ok(IpAddr::from([0xfd00, 0xdead, 0xbeef, 0, 0, 0, 0, 2])),
189 };
190
191 let result = get_http_rpc_host_with_resolver(resolver);
192 assert!(result.starts_with('['), "IPv6 should start with '['");
194 assert!(result.ends_with(']'), "IPv6 should end with ']'");
195 assert_eq!(result, "[fd00:dead:beef::2]");
196 }
197
198 #[test]
199 fn test_ipv4_address_not_bracketed() {
200 let resolver = MockIpResolver {
201 ipv4_result: Ok(IpAddr::from([10, 0, 0, 1])),
202 ipv6_result: Err(Error::LocalIpAddressNotFound),
203 };
204
205 let result = get_http_rpc_host_with_resolver(resolver);
206 assert!(!result.contains('['), "IPv4 should not contain '['");
208 assert_eq!(result, "10.0.0.1");
209 }
210}