use ipinfo::{IpDetails, IpInfo, IpInfoConfig}; use regex::Regex; use rocket::serde::{json::Json, Serialize}; use rocket_client_addr::ClientRealAddr; use rocket::State; use crate::haversine::Units; use crate::serialized_ip_info::IpDetailsDef; use crate::util::{get_client_server_distance_string, get_ip_type, Config}; #[derive(FromForm)] pub struct GetIPOptions { #[field(default = true)] isp: bool, #[field(default = Units::Kilometers)] distance: Units, } #[serde_as] #[skip_serializing_none] #[derive(Serialize)] #[serde(crate = "rocket::serde", rename_all = "camelCase")] pub struct GetIPResponse { processed_string: Option, #[serde_as(as = "Option")] raw_isp_info: Option, } #[get("/getIP?")] pub async fn get_ip(client_addr: &ClientRealAddr, opts: GetIPOptions, state: &State) -> Json { let mut result = GetIPResponse { processed_string: None, raw_isp_info: None, }; let ip = client_addr.ip.to_string().replace("::ffff:", ""); let (processed_string, is_special_ip) = get_ip_type(&ip); result.processed_string = Some(processed_string); if is_special_ip { return Json(result); } if opts.isp { let config = state.inner(); let ipinfo = get_ipinfo(&ip, &config).await; result.raw_isp_info = Some(ipinfo.to_owned()); let org_regex = Regex::new(r"AS\d+\s").unwrap(); let org = &ipinfo.org; let mut isp = org_regex .replace_all(org.as_deref().unwrap(), "") .as_ref() .to_string(); if isp.is_empty() { isp = String::from("Unknown ISP"); } if !ipinfo.country.is_empty() { isp = format!("{}, {}", &isp, &ipinfo.country); } if !ipinfo.loc.is_empty() { let distance = get_client_server_distance_string(ipinfo.loc, opts.distance, config); isp = format!("{} ({})", &isp, &distance); } result.processed_string = Some(format!("{} - {}", &result.processed_string.unwrap(), &isp)); } Json(result) } #[get("/getIP.php?")] pub async fn get_ip_php(client_addr: &ClientRealAddr, opts: GetIPOptions, state: &State) -> Json { get_ip(client_addr, opts, state).await } #[get("/backend/getIP.php?")] pub async fn get_backend_ip_php( client_addr: &ClientRealAddr, opts: GetIPOptions, state: &State, ) -> Json { get_ip(client_addr, opts, state).await } pub async fn get_ipinfo(ip: &str, config: &Config) -> IpDetails { let ipconfig = IpInfoConfig { token: Some(config.ipinfo_token.to_string()), ..Default::default() }; let mut ipinfo_client = IpInfo::new(ipconfig).expect("should construct"); let res = ipinfo_client.lookup(&[ip]).unwrap(); let ipinfo = res.get(ip).unwrap(); ipinfo.to_owned() }