Skip to main content

longport_httpcli/
geo.rs

1use std::{cell::RefCell, time::Duration};
2
3// because we may call `is_cn` multi times in a short time, we cache the result
4thread_local! {
5    static REGION: RefCell<Option<String>> = const { RefCell::new(None) };
6}
7
8async fn region() -> Option<String> {
9    // check user defined REGION
10    if let Ok(region) = std::env::var("LONGPORT_REGION") {
11        return Some(region);
12    }
13
14    // check network connectivity
15    // make sure block_on doesn't block the outer tokio runtime
16    ping().await
17}
18
19async fn ping() -> Option<String> {
20    if let Some(region) = REGION.with_borrow(Clone::clone) {
21        return Some(region.clone());
22    }
23
24    let Ok(resp) = reqwest::Client::new()
25        .get("https://api.lbkrs.com/_ping")
26        .timeout(Duration::from_secs(1))
27        .send()
28        .await
29    else {
30        return None;
31    };
32    let region = resp
33        .headers()
34        .get("X-Ip-Region")
35        .and_then(|v| v.to_str().ok())?;
36    REGION.set(Some(region.to_string()));
37    Some(region.to_string())
38}
39
40/// do the best to guess whether the access point is in China Mainland or not
41pub async fn is_cn() -> bool {
42    region()
43        .await
44        .is_some_and(|region| region.eq_ignore_ascii_case("CN"))
45}