use axum::Json;
use rand::seq::SliceRandom;
use reqwest::{Client, Error, Proxy, StatusCode};
use serde_json::Value;
use std::time::Duration;
use tracing::{error, trace, warn};
const IP_API_ENDPOINT: &str = "http://ip-api.com/json/";
const MAX_RETRIES: usize = 5;
const USER_AGENTS: &[&str] = &[
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
"Mozilla/5.0 (iPhone; CPU iPhone OS 13_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1",
];
const PROXIES: &[&str] = &[
"http://34.81.160.132:80", "http://34.87.84.105:80", "http://117.54.114.102:80", "http://47.178.24.220:80", "http://160.86.242.23:8080", "http://20.26.249.29:8080", "http://198.49.68.80:80", "http://154.64.226.138:80", "http://89.213.0.29:80", "http://51.222.161.115:80", "http://195.181.172.220:8080", "http://41.169.69.91:3128", "http://85.215.64.49:80", "http://162.223.90.130:80", "http://23.247.136.245:80", "http://133.18.234.13:80", "http://41.204.53.19:80", "http://41.204.53.30:80", ];
fn get_random_user_agent() -> &'static str {
USER_AGENTS.choose(&mut rand::thread_rng()).unwrap()
}
fn configure_client(use_proxy: bool) -> Result<Client, Error> {
let mut client_builder = reqwest::Client::builder().timeout(Duration::from_secs(10));
if use_proxy {
let proxy_url = PROXIES.choose(&mut rand::thread_rng()).unwrap();
let proxy = Proxy::all(*proxy_url)?;
client_builder = client_builder.proxy(proxy);
trace!("Proxy enabled: using proxy {}", proxy_url);
} else {
trace!("Proxy disabled: connecting directly");
}
client_builder.build()
}
pub async fn get_geolocation(info: &String, use_proxy: bool) -> Result<Json<Value>, Error> {
let mut attempts = 0;
while attempts < MAX_RETRIES {
attempts += 1;
let user_agent = get_random_user_agent();
let client = match configure_client(use_proxy) {
Ok(c) => c,
Err(e) => {
warn!("Error configuring client: {:?}", e);
continue; }
};
trace!(
"Attempting request using User-Agent: '{}' (Attempt {}/{})",
user_agent,
attempts,
MAX_RETRIES
);
let response = client
.get(format!("{}{}", IP_API_ENDPOINT, info))
.header("User-Agent", user_agent)
.send()
.await;
match response {
Ok(resp) => {
if resp.status().is_success() {
trace!("Request succeeded with status: {}", resp.status());
let response_json: Value = resp.json().await?;
return Ok(Json(response_json));
} else {
warn!(
"Request failed with status: {} (Attempt {}/{})",
resp.status(),
attempts,
MAX_RETRIES
);
if resp.status() == StatusCode::TOO_MANY_REQUESTS {
warn!("Too many requests, retrying after a delay...");
tokio::time::sleep(Duration::from_secs(2)).await;
}
}
}
Err(e) => {
error!(
"Request error: {:?} (Attempt {}/{})",
e, attempts, MAX_RETRIES
);
}
}
}
Ok(Json(serde_json::json!({
"error": "Max retries reached"
})))
}