use anyhow::{Error, anyhow};
use reqwest::{
Client,
Response,
header::COOKIE,
};
use crate::{
data_models::ApiErrors,
utils::{
generate_xcsrf,
Session,
},
};
#[allow(dead_code)]
pub enum HttpMethod {
Get,
Post,
Put,
Delete,
Patch,
}
#[allow(dead_code)]
pub enum HttpProtocol {
Http,
Https,
}
impl ToString for HttpProtocol {
fn to_string(&self) -> String {
match self {
Self::Http => String::from("http:"),
Self::Https => String::from("https:"),
}
}
}
pub struct HttpsRequest<'a> {
pub method: HttpMethod,
pub protocol: HttpProtocol,
pub url: String,
pub session: Option<&'a Session>,
}
pub async fn http_request<'a>(request: HttpsRequest<'_>) -> Result<Response, Error> {
let client = Client::new();
let url = format!("{}{}", request.protocol.to_string(), request.url);
let mut builder = match &request.method {
HttpMethod::Get => client.get(url),
HttpMethod::Post => client.post(url),
HttpMethod::Put => client.put(url),
HttpMethod::Delete => client.delete(url),
HttpMethod::Patch => client.patch(url),
};
let session = request.session;
if let Some(session) = session {
let cookie = session.get_cookie();
if let Some(cookie) = cookie {
builder = builder
.header(COOKIE, format!(".ROBLOSECURITY={};", &cookie))
.header("x-csrf-token", generate_xcsrf(cookie).await?)
}
}
let response = builder.send().await?;
let status_code = response.status();
if status_code.is_success() {
return Ok(response);
}
if status_code.is_client_error() {
if status_code.as_u16() == 429 {
return Err(anyhow!("429: Too many requests."))
}
let api_errors = response.json::<ApiErrors>().await?;
let err_string = api_errors.errors.iter()
.map(|error| error.message.to_owned())
.collect::<Vec<_>>().join(" |<<>>| ");
return Err(anyhow!("Error message from the API: {}", err_string));
}
if status_code.is_server_error() {
return Err(anyhow!("Server error: {:?}", response));
}
Err(anyhow!("Unknown error!: {:?}", response))
}