use anyhow::{bail, Context, Result};
use reqwest::Client;
use serde::Deserialize;
use serde::Serialize;
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
#[serde(rename_all = "camelCase")]
pub struct Info {
pub status: String,
pub message: Option<String>,
pub query: String,
pub country: Option<String>,
pub city: Option<String>,
pub region_name: Option<String>,
pub isp: Option<String>,
}
pub async fn fetch_geo_info(
target: &str,
http_client: &Client,
) -> Result<Info> {
let url = format!("http://ip-api.com/json/{target}");
let response = http_client
.get(&url)
.send()
.await
.with_context(|| format!("Failed to send request to {url}"))?;
if !response.status().is_success() {
bail!(
"Geolocation API request failed with status: {}",
response.status()
);
}
let geo_info = response
.json::<Info>()
.await
.with_context(|| "Failed to deserialize Geolocation API response")?;
if geo_info.status != "success" {
let error_message = geo_info
.message
.unwrap_or_else(|| "Unknown API error".to_string());
bail!("Geolocation API indicated failure: {error_message}");
}
Ok(geo_info)
}