ip_lookup/
ip.rs

1/* src/ip.rs */
2
3use rand::seq::SliceRandom;
4use std::time::Duration;
5
6pub fn get_public_ip_addr() -> Option<String> {
7    let sources = vec![
8        ("https://icanhazip.com/", false), // plain text
9        ("https://api.ip.sb/ip", false), // plain text
10        ("https://api.ipsimple.org/ipv4?format=json", true), // json {"ip": ...}
11        ("https://api.ipify.org/?format=json", true), // json {"ip": ...}
12    ];
13
14    let client = reqwest::blocking::Client::builder()
15        .timeout(Duration::from_secs(3))
16        .build()
17        .unwrap();
18
19    let mut rng = rand::thread_rng();
20    let mut shuffled = sources.clone();
21    shuffled.shuffle(&mut rng);
22
23    for (url, is_json) in shuffled {
24        if let Ok(resp) = client.get(url).send() {
25            if is_json {
26                if let Ok(json) = resp.json::<serde_json::Value>() {
27                    if let Some(ip) = json.get("ip").and_then(|v| v.as_str()) {
28                        return Some(ip.to_string());
29                    }
30                }
31            } else if let Ok(text) = resp.text() {
32                let ip = text.trim().to_string();
33                if !ip.is_empty() {
34                    return Some(ip);
35                }
36            }
37        }
38    }
39
40    None
41}