h10 0.6.14

Simple HTTP/1.0 Server
Documentation
use std::{
    sync::{
        atomic::{AtomicBool, Ordering},
        mpsc, Arc,
    },
    thread,
    time::Duration,
};

use crate::{
    constants::MAX_RESPONSE_LENGTH,
    http::{
        request::Request,
        response::Response,
        result::{H10ClientError, H10LibError, H10LibResult},
    },
};

#[derive(Debug)]
pub struct HttpClient;
impl HttpClient {
    pub fn launch<S: ToString>(
        request: Request,
        connection_string: S,
        timeout: Duration,
    ) -> H10LibResult<String> {
        let arc_req_str = Arc::new(request.to_string());
        let cloned_arc_req_str = Arc::clone(&arc_req_str);

        let arc_connect_str = Arc::new(connection_string.to_string());
        let cloned_arc_connect_str = Arc::clone(&arc_connect_str);

        let (tx, rx) = mpsc::channel();
        let should_terminate = Arc::new(AtomicBool::new(false));
        let should_terminate_clone = Arc::clone(&should_terminate);

        let handle = thread::spawn(move || -> H10LibResult<()> {
            let is_done = should_terminate_clone.load(Ordering::SeqCst);

            if !is_done {
                let request = cloned_arc_req_str;
                let connection_string = cloned_arc_connect_str;
                let res_response_str = Self::request(request, connection_string);

                let is_done_after_response = should_terminate_clone.load(Ordering::SeqCst);

                if !is_done_after_response {
                    tx.send(res_response_str?)?;
                }
            }
            Ok(())
        });

        let mut maybe_response: Option<String> = None;

        match rx.recv_timeout(timeout) {
            Ok(response_str) => {
                should_terminate.store(true, Ordering::SeqCst);
                maybe_response = Some(response_str);
            }
            Err(_) => {
                should_terminate.store(true, Ordering::SeqCst);
            }
        };

        match handle.join() {
            Ok(inner) => {
                inner?;
                maybe_response.ok_or(H10LibError::ClientError(H10ClientError::Timeout))
            }
            Err(err) => {
                dbg!(&err);
                Err(H10LibError::ClientError(H10ClientError::InternalError(
                    format!("CLientError: Internal Error: {err:?}"),
                )))
            }
        }
    }

    fn request(request_str: Arc<String>, connect_str: Arc<String>) -> H10LibResult<String> {
        use std::io::{Read, Write};
        use std::net::TcpStream;

        let mut response_buffer: [u8; MAX_RESPONSE_LENGTH] = [0; MAX_RESPONSE_LENGTH];

        let mut stream = TcpStream::connect(connect_str.as_str())?;

        stream.write_all(request_str.as_bytes())?;

        stream.read(&mut response_buffer)?;

        let response = Response::parse(&response_buffer)?;

        Ok(response.to_string())
    }
}