1pub fn get_local_ip() -> Option<String> {
5 let socket = std::net::UdpSocket::bind("0.0.0.0:0").ok()?;
7 socket.connect("8.8.8.8:80").ok()?;
8 socket.local_addr().ok().map(|addr| addr.ip().to_string())
9}
10
11pub fn build_url_with_params(base_url: &str, params: &[(&str, &str)]) -> String {
13 let mut url = base_url.to_string();
14 if !params.is_empty() {
15 url.push('?');
16 for (i, (key, value)) in params.iter().enumerate() {
17 if i > 0 {
18 url.push('&');
19 }
20 url.push_str(&format!("{}={}", key, urlencoding::encode(value)));
21 }
22 }
23 url
24}
25
26mod urlencoding {
28 pub fn encode(s: &str) -> String {
29 let mut result = String::new();
30 for byte in s.bytes() {
31 match byte {
32 b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => {
33 result.push(byte as char);
34 }
35 _ => {
36 result.push_str(&format!("%{:02X}", byte));
37 }
38 }
39 }
40 result
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn test_url_encoding() {
50 assert_eq!(urlencoding::encode("hello"), "hello");
51 assert_eq!(urlencoding::encode("hello world"), "hello%20world");
52 assert_eq!(urlencoding::encode("a+b"), "a%2Bb");
53 }
54
55 #[test]
56 fn test_build_url_with_params() {
57 let url = build_url_with_params("https://api.example.com", &[
58 ("key", "value"),
59 ("foo", "bar"),
60 ]);
61 assert!(url.contains("key=value"));
62 assert!(url.contains("foo=bar"));
63 }
64}