httpio 0.2.4

A transport-agnostic, async HTTP/1.1 client library for any runtime.
Documentation
use crate::enums::http_body::HttpBody;
use crate::enums::http_error::HttpError;
use crate::enums::http_request_method::HttpRequestMethod;
use crate::enums::http_version::HttpVersion;
use crate::structures::header::header_list::HttpHeaderList;
use crate::structures::http_message::HttpMessage;
use crate::structures::http_request_builder::HttpRequestBuilder;
use crate::structures::http_stream::HttpStream;
use futures::{AsyncBufRead, AsyncWrite, AsyncWriteExt};
use log::{LogLevel, debug_lazy_with, structs::logger::Logger, trace_lazy_with};

pub struct HttpConnection<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> {
    pub stream: HttpStream<R, W>,
    pub request_builder: HttpRequestBuilder,
    pub logger: Logger,
}

impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> HttpConnection<R, W> {
    pub fn new(
        stream_reader: R,
        stream_writer: W,
        http_version: HttpVersion,
        host: &str,
        request_headers: HttpHeaderList,
        logger: Logger,
    ) -> Result<Self, HttpError> {
        let stream = HttpStream::new(stream_reader, stream_writer);
        let request_builder = HttpRequestBuilder::new(http_version, request_headers, host);
        Ok(HttpConnection {
            stream,
            request_builder,
            logger,
        })
    }

    pub async fn send_request(
        &mut self,
        method: HttpRequestMethod,
        path_query: &str,
        request_headers: HttpHeaderList,
        body: HttpBody,
    ) -> Result<usize, HttpError> {
        let message = self
            .request_builder
            .build_request(method, path_query, request_headers, body);
        match self.logger.level() {
            LogLevel::Debug => debug_lazy_with!(self.logger, || "Http Request: {}{}", &self.request_builder.host, path_query),
            LogLevel::Trace => trace_lazy_with!(self.logger, || "Http Request: {}\n{}", &self.request_builder.host, &message),
            _ => (),
        }
        let bytes = message.as_bytes(true);
        self.stream.writer.write_all(&bytes).await?;
        self.stream.writer.flush().await?;
        Ok(bytes.len())
    }

    pub async fn send_get_request(
        &mut self,
        path_query: &str,
        request_headers: HttpHeaderList,
    ) -> Result<usize, HttpError> {
        self.send_request(
            HttpRequestMethod::Get,
            path_query,
            request_headers,
            HttpBody::None,
        )
        .await
    }

    pub async fn read_response(&mut self) -> Result<HttpMessage, HttpError> {
        let message = HttpMessage::read(&mut self.stream.reader).await?;
        match self.logger.level() {
            LogLevel::Debug => debug_lazy_with!(self.logger, || "Http Response: {}", &message.start_line),
            LogLevel::Trace => trace_lazy_with!(self.logger, || "Http Response: {}", &message),
            _ => (),
        }
        Ok(message)
    }

    pub fn host(&self) -> &str {
        &self.request_builder.host
    }
}