rowrap 0.0.0

A wrapper for the Roblox API.
Documentation
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);
    }

    // Roblox provides an error message for every client error code except 429.
    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))
}