use std::net::ToSocketAddrs;
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct IpInfo {
pub ip: Option<String>,
pub city: Option<String>,
pub region: Option<String>,
pub country: Option<String>,
}
#[derive(Debug, Clone)]
pub struct IcloudStorageAddress {
pub address: String, pub resolved_ip: Option<String>, pub ip: Option<String>, pub country_code: Option<String>, pub region: Option<String>, pub city: Option<String>, pub note: Option<String>, }
pub fn storage_address() -> IcloudStorageAddress {
let host = "content.icloud.com";
let address = format!("https://{}", host);
let ipinfo: Option<IpInfo> = match reqwest::blocking::get("https://ipinfo.io/json") {
Ok(resp) => match resp.text() {
Ok(text) => serde_json::from_str::<IpInfo>(&text).ok(),
Err(_) => None,
},
Err(_) => None,
};
let resolved_ip = (host, 443)
.to_socket_addrs()
.ok()
.and_then(|mut iter| iter.next())
.map(|addr| addr.ip().to_string());
let note = ipinfo
.as_ref()
.and_then(|i| i.country.clone())
.map(|cc| {
if cc == "CN" {
String::from(
"中国大陆用户的 iCloud 数据由云上贵州(GCBD)托管;域名解析与实际存储位置由苹果与CDN动态调度,此地址为近似参考。",
)
} else {
String::from(
"该地址为基于DNS解析的就近节点近似结果;实际数据位置和访问路径由苹果与CDN动态决定。",
)
}
});
IcloudStorageAddress {
address,
resolved_ip,
ip: ipinfo.as_ref().and_then(|i| i.ip.clone()),
country_code: ipinfo.as_ref().and_then(|i| i.country.clone()),
region: ipinfo.as_ref().and_then(|i| i.region.clone()),
city: ipinfo.as_ref().and_then(|i| i.city.clone()),
note,
}
}
pub fn storage_address_offline() -> IcloudStorageAddress {
IcloudStorageAddress {
address: "https://content.icloud.com".to_string(),
resolved_ip: None,
ip: None,
country_code: None,
region: None,
city: None,
note: Some(String::from("离线回退:未能获取IP或DNS解析,返回固定入口域名。")),
}
}
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}