1use std::time::Duration;
2
3use reqwest::{RequestBuilder, StatusCode, header::HeaderMap};
4
5pub mod error;
6
7#[cfg(feature = "oauth1a")]
8pub mod oauth1a;
9
10#[cfg(feature = "oauth2")]
11pub mod oauth2;
12
13pub use reqwest;
14
15use crate::error::Error;
16
17pub(crate) async fn execute_retry<T>(
18 f: impl Fn() -> RequestBuilder,
19 try_count: usize,
20 retry_millis: u64,
21) -> Result<(T, StatusCode, HeaderMap), Error>
22where
23 T: serde::de::DeserializeOwned,
24{
25 for i in 0..try_count {
26 let req = f();
27 let res = req.send().await?;
28 let status = res.status();
29 let headers = res.headers().clone();
30 if status.is_success() {
31 let json: T = res.json().await?;
32 return Ok((json, status, headers));
33 } else if status.is_client_error() {
34 let body = res.text().await.unwrap_or_default();
35 return Err(Error::ClientError(body, status, headers));
36 }
37 if i + 1 < try_count {
38 let jitter: u64 = rand::random::<u64>() % retry_millis;
40 let exp_backoff = 2u64.pow(i as u32) * retry_millis;
41 let retry_duration = Duration::from_millis(exp_backoff + jitter);
42 tokio::time::sleep(retry_duration).await;
43 } else {
44 let body = res.text().await.unwrap_or_default();
45 return Err(Error::RetryOver(body, status, headers));
46 }
47 }
48 unreachable!()
49}
50
51pub(crate) async fn execute_retry_body(
52 f: impl Fn() -> RequestBuilder,
53 try_count: usize,
54 retry_millis: u64,
55) -> Result<(String, StatusCode, HeaderMap), Error>
56{
57 for i in 0..try_count {
58 let req = f();
59 let res = req.send().await?;
60 let status = res.status();
61 let headers = res.headers().clone();
62 if status.is_success() {
63 let body = res.text().await?;
64 return Ok((body, status, headers));
65 } else if status.is_client_error() {
66 let body = res.text().await.unwrap_or_default();
67 return Err(Error::ClientError(body, status, headers));
68 }
69 if i + 1 < try_count {
70 let jitter: u64 = rand::random::<u64>() % retry_millis;
72 let exp_backoff = 2u64.pow(i as u32) * retry_millis;
73 let retry_duration = Duration::from_millis(exp_backoff + jitter);
74 tokio::time::sleep(retry_duration).await;
75 } else {
76 let body = res.text().await.unwrap_or_default();
77 return Err(Error::RetryOver(body, status, headers));
78 }
79 }
80 unreachable!()
81}