Skip to main content

hac_core/net/
request_manager.rs

1use crate::collection::types::{BodyType, Request};
2use crate::net::request_strategies::{http_strategy::HttpResponse, RequestStrategy};
3use crate::text_object::{Readonly, TextObject};
4
5use std::sync::{Arc, RwLock};
6use std::time::Duration;
7
8use reqwest::header::{HeaderMap, HeaderValue};
9use tokio::sync::mpsc::UnboundedSender;
10
11#[derive(Debug, PartialEq)]
12pub struct Response {
13    pub body: Option<String>,
14    pub pretty_body: Option<TextObject<Readonly>>,
15    pub headers: Option<HeaderMap<HeaderValue>>,
16    pub duration: Duration,
17    pub status: Option<reqwest::StatusCode>,
18    pub headers_size: Option<u64>,
19    pub body_size: Option<u64>,
20    pub size: Option<u64>,
21    pub is_error: bool,
22    pub cause: Option<String>,
23}
24
25pub struct RequestManager;
26
27impl RequestManager {
28    pub async fn handle<S>(strategy: S, request: Request) -> Response
29    where
30        S: RequestStrategy,
31    {
32        strategy.handle(request).await
33    }
34}
35
36pub enum ContentType {
37    TextPlain,
38    TextHtml,
39    TextCss,
40    TextJavascript,
41    ApplicationJson,
42    ApplicationXml,
43}
44
45impl From<&str> for ContentType {
46    fn from(value: &str) -> Self {
47        match value {
48            _ if value.to_ascii_lowercase().contains("application/json") => Self::ApplicationJson,
49            _ if value.to_ascii_lowercase().contains("application/xml") => Self::ApplicationXml,
50            _ if value.to_ascii_lowercase().contains("text/plain") => Self::TextPlain,
51            _ if value.to_ascii_lowercase().contains("text/plain") => Self::TextPlain,
52            _ if value.to_ascii_lowercase().contains("text/html") => Self::TextHtml,
53            _ if value.to_ascii_lowercase().contains("text/css") => Self::TextCss,
54            _ if value.to_ascii_lowercase().contains("text/javascript") => Self::TextJavascript,
55            _ => Self::TextPlain,
56        }
57    }
58}
59
60#[tracing::instrument(skip_all)]
61pub fn handle_request(request: &Arc<RwLock<Request>>, response_tx: UnboundedSender<Response>) {
62    let request = request.read().unwrap().clone();
63    tokio::spawn(async move {
64        let response = match request.body_type.as_ref() {
65            // if we dont have a body type, this is a GET request, so we use HTTP strategy
66            None => RequestManager::handle(HttpResponse, request).await,
67            Some(body_type) => match body_type {
68                BodyType::Json => RequestManager::handle(HttpResponse, request).await,
69            },
70        };
71
72        response_tx
73            .send(response)
74            .is_err()
75            .then(|| std::process::abort());
76    });
77}