1use crate::error::IdentityError;
2
3pub async fn resolve_timezone(
6 explicit: Option<&str>,
7 proxy: Option<&str>,
8) -> Result<String, IdentityError> {
9 if let Some(tz) = explicit {
10 return Ok(tz.to_string());
11 }
12
13 fetch_timezone_from_ipapi(proxy).await
14}
15
16async fn fetch_timezone_from_ipapi(proxy: Option<&str>) -> Result<String, IdentityError> {
19 let mut builder = reqwest::Client::builder();
20 if let Some(proxy_url) = proxy {
21 builder = builder.proxy(
22 reqwest::Proxy::all(proxy_url)
23 .map_err(|e| IdentityError::TimezoneError(format!("invalid proxy: {e}")))?,
24 );
25 }
26 let client = builder
27 .build()
28 .map_err(|e| IdentityError::TimezoneError(format!("http client error: {e}")))?;
29
30 let resp: serde_json::Value = client
31 .get("http://ip-api.com/json/?fields=timezone")
32 .send()
33 .await
34 .map_err(|e| IdentityError::TimezoneError(format!("ip-api request failed: {e}")))?
35 .json()
36 .await
37 .map_err(|e| IdentityError::TimezoneError(format!("ip-api parse failed: {e}")))?;
38
39 resp.get("timezone")
40 .and_then(|v| v.as_str())
41 .map(|s| s.to_string())
42 .ok_or_else(|| IdentityError::TimezoneError("ip-api returned no timezone".into()))
43}