1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::result::{Error, Result};
use backoff::{future, ExponentialBackoff};
use log::warn;
use reqwest::StatusCode;
const LOG_TARGET: &str = "boardgamegeek::Client";
pub struct Client {
http_client: reqwest::Client,
}
async fn collect(response: reqwest::Response) -> Result<String> {
match response.text().await {
Ok(text) => Ok(text),
Err(_err) => Err(Error::BadResponse),
}
}
impl Client {
pub fn new() -> Self {
Self {
http_client: reqwest::Client::builder()
.redirect(reqwest::redirect::Policy::none())
.build()
.unwrap(),
}
}
pub async fn get(&self, url: &str) -> Result<String> {
future::retry(ExponentialBackoff::default(), || async {
let result = self.http_client.get(url).send().await;
if let Err(_err) = result {
return Err(backoff::Error::Permanent(Error::ConnectionFailed));
}
let response = result.unwrap();
match response.status() {
StatusCode::TOO_MANY_REQUESTS => {
warn!(target: LOG_TARGET, "Received 429: {:?}", response);
Err(backoff::Error::Transient(Error::TooManyRequests))
}
StatusCode::OK => Ok(collect(response).await?),
code => Err(backoff::Error::Permanent(Error::RequestFailed(
code.as_u16(),
))),
}
})
.await
}
pub async fn get_redirect_location(&self, url: &str) -> Result<Option<String>> {
let result = self.http_client.get(url).send().await;
if let Err(_err) = result {
return Err(Error::ConnectionFailed);
}
let response = result.unwrap();
match response.status() {
StatusCode::FOUND => match response.headers().get("Location") {
Some(v) => Ok(Some(v.to_str().unwrap().to_owned())),
None => Ok(None),
},
code => Err(Error::RequestFailed(code.as_u16())),
}
}
pub async fn get_with_202_check(&self, url: &str) -> Result<String> {
future::retry(backoff::ExponentialBackoff::default(), || async {
match self.get(url).await {
Err(Error::RequestFailed(202)) => {
warn!(target: LOG_TARGET, "Received 202. Retrying...");
Err(backoff::Error::Transient(Error::RequestFailed(202)))
}
Err(e) => Err(backoff::Error::Permanent(e)),
Ok(r) => Ok(r),
}
})
.await
}
}