use crate::constant;
use crate::error::IpApiError;
use crate::model::ip_response::ErrorResponse;
use governor::DefaultDirectRateLimiter;
#[cfg(feature = "blocking")]
use reqwest::blocking;
use reqwest::RequestBuilder;
use serde::de::DeserializeOwned;
#[cfg(feature = "blocking")]
use std::thread::sleep;
#[cfg(feature = "blocking")]
use std::time::Duration;
pub async fn perform_get_request<T>(
request_builder: RequestBuilder,
limiter: &Option<DefaultDirectRateLimiter>,
) -> Result<T, IpApiError>
where
T: DeserializeOwned,
{
wait_for_rate_limiter(limiter).await;
let response = request_builder.send().await?;
let json = response.text().await?;
process_result(json)
}
#[cfg(feature = "blocking")]
pub fn perform_blocking_get_request<T>(
request_builder: blocking::RequestBuilder,
limiter: &Option<DefaultDirectRateLimiter>,
) -> Result<T, IpApiError>
where
T: DeserializeOwned,
{
block_until_rate_limiter(limiter);
let response = request_builder.send()?;
let json = response.text()?;
process_result::<T>(json)
}
fn process_result<T>(json: String) -> Result<T, IpApiError>
where
T: DeserializeOwned,
{
if let Some(error) = validate_result(json.clone()) {
return Err(error);
}
parse_result::<T>(&json)
}
fn validate_result(json: String) -> Option<IpApiError> {
if json.contains("\"status\":\"fail\"") {
return match serde_json::from_str::<ErrorResponse>(&json) {
Ok(error_response) => match error_response.message.as_str() {
constant::ERROR_RESERVED_RANGE => Some(IpApiError::ReservedRange(error_response)),
constant::ERROR_INVALID_QUERY => Some(IpApiError::InvalidQuery(error_response)),
_ => Some(IpApiError::Unknown(json.clone())),
},
Err(err) => Some(IpApiError::JsonParseError(err)),
};
}
None
}
fn parse_result<T>(json: &str) -> Result<T, IpApiError>
where
T: DeserializeOwned,
{
match serde_json::from_str::<T>(json) {
Ok(response) => Ok(response),
Err(err) => Err(IpApiError::JsonParseError(err)),
}
}
async fn wait_for_rate_limiter(limiter: &Option<DefaultDirectRateLimiter>) {
if let Some(limiter) = limiter {
limiter.until_ready().await
}
}
#[cfg(feature = "blocking")]
fn block_until_rate_limiter(limiter: &Option<DefaultDirectRateLimiter>) {
if let Some(limiter) = limiter {
while limiter.check().is_err() {
sleep(Duration::new(1, 0));
}
}
}