use reqwest::header::*;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::thread::sleep;
use std::time::Duration;
use serde_json::json;
pub type HttpResult<T> = Result<T, HttpError>;
#[derive(Debug, Clone)]
pub enum HttpError {
ParseJson{message: String},
BadToken,
TooManyTries{num_tries: u32},
NotFound{message: String},
TooManyRequests{message: String}
}
#[derive(Debug)]
pub struct Client {
client: reqwest::blocking::Client
}
pub fn get<T: DeserializeOwned + Send + 'static>(url: &str, times_to_try: u32) -> HttpResult<T> {
let url_copy = url.to_string();
let result = std::thread::spawn( move || {
Client::new().get::<T>(&url_copy.to_string(), times_to_try)
}).join().unwrap();
result
}
impl Client {
pub fn new() -> Client {
Client {
client: reqwest::blocking::Client::new()
}
}
pub fn get<T: DeserializeOwned>(&self, url: &str, times_to_try: u32) -> HttpResult<T> {
self._get(url, times_to_try, 0, Duration::from_secs(1))
}
pub fn get_as_text(&self, url: &str) -> String {
return
reqwest::blocking::get(url).unwrap()
.text().unwrap()
}
pub fn post<T: Serialize>(&self, url: &str, data: T)
where T: std::fmt::Debug
{
let response = self.client
.post(url)
.header(CONTENT_TYPE, "application/json")
.header(ACCEPT, "application/json")
.json(&data)
.send()
.unwrap()
.text().unwrap();
dbg!(response);
}
fn _get<T: DeserializeOwned>(
&self,
url: &str,
times_to_try: u32,
mut tries: u32,
mut incremental_wait_time: Duration
)
-> HttpResult<T> {
if tries >= times_to_try { return Err(HttpError::TooManyTries{num_tries: tries})}
let response = reqwest::blocking::Client::new()
.get(url)
.header(CONTENT_TYPE, "application/json")
.send()
.unwrap();
match response.status() {
reqwest::StatusCode::OK => {
match response.json::<T>() {
Ok(parsed) => Ok(parsed),
Err(_) => Err(HttpError::ParseJson{message: "Hm, the response didn't match the shape we expected.".to_string()}),
}
}
reqwest::StatusCode::UNAUTHORIZED => {
Err(HttpError::BadToken)
}
reqwest::StatusCode::NOT_FOUND => {
Err(
HttpError::NotFound {
message:
"Response 404, probably means the server couldn't find the data you were looking for.".to_string()
}
)
}
reqwest::StatusCode::BAD_REQUEST => {
println!("💥 Caught BAD_REQUEST");
dbg!(&response.status());
tries += 1;
sleep(Duration::from_secs(1));
self._get(url, times_to_try, tries, incremental_wait_time)
}
reqwest::StatusCode::TOO_MANY_REQUESTS => {
println!("🥷🏾 {} be complainin' 'bout too many requests!", url);
println!("🥷🏾 So I'm waiting {} from_secs and trying again.", incremental_wait_time.as_secs());
println!("🥷🏾 This was try {} of {}.", tries, times_to_try);
sleep(incremental_wait_time);
incremental_wait_time *= 2;
tries += 1;
self._get(url, times_to_try, tries, incremental_wait_time)
}
_ => {
dbg!("💥 Uncaught http error, response.status() was: ", response.status(),"/n");
tries += 1;
sleep(incremental_wait_time);
incremental_wait_time *= 2;
self._get(url, times_to_try, tries, incremental_wait_time)
}
}
}
}