shors 0.12.6

Transport layer for cartridge + tarantool-module projects.
Documentation
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::collections::HashMap;
use std::fmt::{Display, Formatter};

#[cfg(feature = "open-api")]
pub mod openapi;
pub mod route;
pub mod server;

/// Currently tarantool/http support Http/1.0 and Http/1.1
#[derive(Debug)]
pub enum HTTPProtocol {
    HTTP10,
    HTTP11,
    HTTP20,
    HTTP30,
    Unknown,
}

impl Display for HTTPProtocol {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            HTTPProtocol::HTTP10 => f.write_str("HTTP/1.0"),
            HTTPProtocol::HTTP11 => f.write_str("HTTP/1.1"),
            HTTPProtocol::HTTP20 => f.write_str("HTTP/2.0"),
            HTTPProtocol::HTTP30 => f.write_str("HTTP/3.0"),
            HTTPProtocol::Unknown => f.write_str("unknown"),
        }
    }
}

impl Default for HTTPProtocol {
    fn default() -> Self {
        Self::HTTP11
    }
}

impl From<[i32; 2]> for HTTPProtocol {
    fn from(proto: [i32; 2]) -> Self {
        match proto[0] {
            1 if proto[1] == 0 => HTTPProtocol::HTTP10,
            1 if proto[1] == 1 => HTTPProtocol::HTTP11,
            2 if proto[1] == 0 => HTTPProtocol::HTTP20,
            3 if proto[1] == 0 => HTTPProtocol::HTTP30,
            _ => HTTPProtocol::Unknown,
        }
    }
}

#[derive(Debug, Default)]
pub struct Peer {
    pub host: Option<String>,
    pub port: Option<u32>,
    pub family: Option<String>,
}

impl From<HashMap<String, String>> for Peer {
    fn from(mut peer: HashMap<String, String>) -> Self {
        Self {
            host: peer.remove("host"),
            port: peer.remove("port").and_then(|v| v.parse::<u32>().ok()),
            family: peer.remove("family"),
        }
    }
}

/// Http request.
#[derive(Debug, Default)]
pub struct Request {
    pub method: String,
    pub path: String,
    pub query: String,
    pub headers: HashMap<String, String>,
    pub stash: HashMap<String, String>,
    pub body: Vec<u8>,
    pub proto: HTTPProtocol,
    pub peer: Peer,
}

impl Request {
    /// Parse request body .
    pub fn parse<T: DeserializeOwned>(&self) -> Result<T, serde_json::Error> {
        serde_json::from_slice::<'_, T>(&self.body)
    }

    /// Parse request's query into given type.
    pub fn query<T: DeserializeOwned>(&self) -> Result<T, serde_qs::Error> {
        serde_qs::from_str(&self.query)
    }
}

/// Http response.
#[derive(Debug)]
pub struct Response {
    pub status: u32,
    pub headers: HashMap<String, String>,
    pub body: Vec<u8>,
}

impl<T: Serialize> From<T> for Response {
    fn from(data: T) -> Self {
        Self {
            status: 200,
            headers: HashMap::from([(
                "content-type".to_string(),
                "application/json; charset=utf8".to_string(),
            )]),
            body: serde_json::to_vec(&data).unwrap(),
        }
    }
}