ip_api4rs/
request_handler.rs

1//! # Request Handler
2//! This module contains the request handler for the API calls.
3
4use crate::constant;
5use crate::error::IpApiError;
6use crate::model::ip_response::ErrorResponse;
7use governor::DefaultDirectRateLimiter;
8#[cfg(feature = "blocking")]
9use reqwest::blocking;
10use reqwest::RequestBuilder;
11use serde::de::DeserializeOwned;
12#[cfg(feature = "blocking")]
13use std::thread::sleep;
14#[cfg(feature = "blocking")]
15use std::time::Duration;
16
17/// Performs a GET request to the API.
18///
19/// # Arguments
20/// * `request_builder` - The request builder to use.
21/// * `limiter` - The rate limiter to use.
22///
23/// # Returns
24/// * `Result<T, ip-api4rs::error::IpApiError>` - The response from the API.
25pub async fn perform_get_request<T>(
26    request_builder: RequestBuilder,
27    limiter: &Option<DefaultDirectRateLimiter>,
28) -> Result<T, IpApiError>
29where
30    T: DeserializeOwned,
31{
32    wait_for_rate_limiter(limiter).await;
33    let response = request_builder.send().await?;
34    let json = response.text().await?;
35    process_result(json)
36}
37
38/// Performs a blocking GET request to the API.
39///
40/// # Arguments
41/// * `request_builder` - The request builder to use.
42/// * `limiter` - The rate limiter to use.
43///
44/// # Returns
45/// * `Result<T, ip-api4rs::error::IpApiError>` - The response from the API.
46#[cfg(feature = "blocking")]
47pub fn perform_blocking_get_request<T>(
48    request_builder: blocking::RequestBuilder,
49    limiter: &Option<DefaultDirectRateLimiter>,
50) -> Result<T, IpApiError>
51where
52    T: DeserializeOwned,
53{
54    block_until_rate_limiter(limiter);
55    let response = request_builder.send()?;
56    let json = response.text()?;
57    process_result::<T>(json)
58}
59
60/// Processes the result from the API.
61/// Checks for errors and parses the result.
62///
63/// # Arguments
64/// * `json` - The json to parse.
65///
66/// # Returns
67/// * `Result<T, ip-api4rs::error::IpApiError>` - The parsed result.
68fn process_result<T>(json: String) -> Result<T, IpApiError>
69where
70    T: DeserializeOwned,
71{
72    if let Some(error) = validate_result(json.clone()) {
73        return Err(error);
74    }
75    parse_result::<T>(&json)
76}
77
78/// Validates the result for errors.
79///
80/// # Arguments
81/// * `json` - The json to parse.
82///
83/// # Returns
84/// * `Option<IpApiError>` - The error if there is one.
85fn validate_result(json: String) -> Option<IpApiError> {
86    if json.contains("\"status\":\"fail\"") {
87        return match serde_json::from_str::<ErrorResponse>(&json) {
88            Ok(error_response) => match error_response.message.as_str() {
89                constant::ERROR_RESERVED_RANGE => Some(IpApiError::ReservedRange(error_response)),
90                constant::ERROR_INVALID_QUERY => Some(IpApiError::InvalidQuery(error_response)),
91                _ => Some(IpApiError::Unknown(json.clone())),
92            },
93            Err(err) => Some(IpApiError::JsonParseError(err)),
94        };
95    }
96    None
97}
98
99/// Parses the result from the API.
100///
101/// # Arguments
102/// * `json` - The json to parse.
103///
104/// # Returns
105/// * `Result<T, ip-api4rs::error::IpApiError>` - The parsed result.
106fn parse_result<T>(json: &str) -> Result<T, IpApiError>
107where
108    T: DeserializeOwned,
109{
110    match serde_json::from_str::<T>(json) {
111        Ok(response) => Ok(response),
112        Err(err) => Err(IpApiError::JsonParseError(err)),
113    }
114}
115
116/// Waits for the rate limiter to be ready.
117async fn wait_for_rate_limiter(limiter: &Option<DefaultDirectRateLimiter>) {
118    if let Some(limiter) = limiter {
119        limiter.until_ready().await
120    }
121}
122
123/// Blocks until the rate limiter is ready.
124#[cfg(feature = "blocking")]
125fn block_until_rate_limiter(limiter: &Option<DefaultDirectRateLimiter>) {
126    if let Some(limiter) = limiter {
127        while limiter.check().is_err() {
128            sleep(Duration::new(1, 0));
129        }
130    }
131}