rusty_blitzcrank/
dispatcher.rs

1pub mod dispatcher {
2    use crate::api_key::*;
3    use crate::types::*;
4    use reqwest::Client;
5    use tokio::time::{sleep, Duration};
6
7    pub async fn get(
8        url: String,
9        api_key: &mut ApiKey,
10        wait_for_rate_limit: bool,
11        endpoint: String,
12    ) -> Result<String, BlitzError> {
13        let is_limited = api_key.ratelimiter.is_limited(endpoint.clone());
14
15        if !wait_for_rate_limit && is_limited {
16            return Err(BlitzError::RateLimited);
17        } else if wait_for_rate_limit && is_limited {
18            sleep(Duration::from_secs(
19                api_key.ratelimiter.wait_for(endpoint.clone()),
20            ))
21            .await;
22        }
23
24        let client = Client::new();
25        api_key.ratelimiter.add_call(endpoint.clone());
26        let response = client
27            .get(url.clone())
28            .header("X-Riot-Token", &api_key.key)
29            .send()
30            .await;
31
32        let mut resp = match response {
33            Ok(d) => d,
34            Err(e) => return Err(BlitzError::RequestError(Some(e.to_string()))),
35        };
36
37        while resp.status().as_u16() == 429 {
38            let wait_time = resp
39                .headers()
40                .get("Retry-After")
41                .and_then(|h| h.to_str().ok())
42                .and_then(|s| s.parse().ok());
43
44            match wait_time {
45                Some(t) => {
46                    if !wait_for_rate_limit {
47                        return Err(BlitzError::RateLimited);
48                    }
49
50                    sleep(Duration::from_secs(t)).await;
51                    resp = match client.get(url.clone()).send().await {
52                        Ok(data) => data,
53                        Err(e) => return Err(BlitzError::RequestError(Some(e.to_string()))),
54                    };
55                }
56                None => break,
57            }
58        }
59
60        if resp.status().is_success() {
61            let data = resp.text().await.map(|b| b.to_owned());
62            match data {
63                Ok(d) => return Ok(d),
64                Err(e) => return Err(BlitzError::RequestError(Some(e.to_string()))),
65            }
66        } else if resp.status().as_u16() == 403 {
67            return Err(BlitzError::Forbidden);
68        } else if resp.status().as_u16() == 404 {
69            return Err(BlitzError::NotFound);
70        }
71
72        return Err(BlitzError::BadStatuscode(resp.status().as_u16()));
73    }
74}