portfu_core 0.1.0

Portfu Core Types and Definitions Library
Documentation
pub mod filters;
pub mod routes;
pub mod service;
pub mod sockets;
pub mod task;
pub mod wrappers;

use crate::service::{BodyType, Service, ServiceRequest};
use async_trait::async_trait;
use http::{HeaderMap, Response, StatusCode};
use http_body_util::BodyExt;
use http_body_util::Full;
use hyper::body::Bytes;
use once_cell::sync::Lazy;
use serde::Deserialize;
use std::fmt::{Debug, Formatter};
use std::io::{Error, ErrorKind};
use std::net::SocketAddr;
use std::sync::Arc;

#[async_trait]
pub trait ServiceHandler {
    fn name(&self) -> &str;
    async fn handle(&self, data: &mut ServiceData) -> Result<(), Error>;
}
impl Debug for (dyn ServiceHandler + Send + Sync + 'static) {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.write_str(self.name())
    }
}

#[async_trait]
impl ServiceHandler for (&'static str, &'static str) {
    fn name(&self) -> &str {
        self.0
    }

    async fn handle(&self, data: &mut ServiceData) -> Result<(), Error> {
        *data.response.body_mut() = Full::new(Bytes::from_static(self.1.as_bytes()));
        Ok(())
    }
}

#[async_trait]
impl ServiceHandler for (&'static str, &'static [u8]) {
    fn name(&self) -> &str {
        self.0
    }

    async fn handle(&self, data: &mut ServiceData) -> Result<(), Error> {
        *data.response.body_mut() = Full::new(Bytes::from_static(self.1));
        Ok(())
    }
}

pub struct ServiceData {
    pub request: ServiceRequest,
    pub response: Response<Full<Bytes>>,
}
impl ServiceData {
    pub fn get_best_guess_public_ip(&self, address: &SocketAddr) -> String {
        if let Some(real_ip) = self.request.request.headers().get("x-real-ip") {
            format!("{:?}", real_ip)
        } else if let Some(forwards) = self.request.request.headers().get("x-forwarded-for") {
            format!("{:?}", forwards)
        } else {
            address.to_string()
        }
    }
}

struct DefaultHandler {}
#[async_trait]
impl ServiceHandler for DefaultHandler {
    fn name(&self) -> &str {
        "DefaultHandler"
    }
    async fn handle(&self, data: &mut ServiceData) -> Result<(), Error> {
        *data.response.status_mut() = StatusCode::NOT_FOUND;
        *data.response.body_mut() = Full::new(Bytes::from(format!(
            "Failed to find Path: {}",
            data.request.request.uri().path()
        )));
        Ok(())
    }
}

pub trait ServiceRegister {
    fn register(self, service_registry: &mut ServiceRegistry);
}

pub static mut STATIC_REGISTRY: Lazy<ServiceRegistry> =
    Lazy::new(|| ServiceRegistry { services: vec![] });

#[derive(Clone, Debug, Default)]
pub struct ServiceRegistry {
    pub services: Vec<Arc<Service>>,
}
impl ServiceRegistry {
    pub fn register(&mut self, service: Service) {
        self.services.push(Arc::new(service));
    }
}

#[async_trait]
pub trait FromRequest<'a>
where
    Self: Sized,
{
    async fn from_request(
        request: &'a mut ServiceRequest,
        var_name: &'a str,
    ) -> Result<Self, Error>;
}

#[derive(Clone)]
pub struct State<T: Send + Sync + 'static>(pub Arc<T>);
impl<T: Send + Sync + 'static> State<T> {
    pub fn inner(&self) -> Arc<T> {
        self.0.clone()
    }
}
impl<T: Send + Sync + 'static> AsRef<T> for State<T> {
    fn as_ref(&self) -> &T {
        self.0.as_ref()
    }
}
#[async_trait]
impl<'a, T: Send + Sync + 'static> FromRequest<'a> for State<T> {
    async fn from_request(request: &'a mut ServiceRequest, _: &'a str) -> Result<Self, Error> {
        request
            .request
            .extensions()
            .get::<Arc<T>>()
            .cloned()
            .map(State)
            .ok_or(Error::new(ErrorKind::NotFound, "Failed to find State"))
    }
}
#[async_trait]
impl<'a> FromRequest<'a> for &'a mut HeaderMap {
    async fn from_request(request: &'a mut ServiceRequest, _: &'a str) -> Result<Self, Error> {
        Ok(request.request.headers_mut())
    }
}

#[async_trait]
impl<'a> FromRequest<'a> for SocketAddr {
    async fn from_request(request: &'a mut ServiceRequest, _: &'a str) -> Result<Self, Error> {
        request
            .get()
            .copied()
            .ok_or(Error::new(ErrorKind::NotFound, "Failed to find SocketAddr"))
    }
}

#[derive(Clone)]
pub struct Path(String);
impl Path {
    pub fn inner(self) -> String {
        self.0
    }
}
#[async_trait]
impl<'a> FromRequest<'a> for Path {
    async fn from_request(
        request: &'a mut ServiceRequest,
        var_name: &'a str,
    ) -> Result<Self, Error> {
        request
            .path
            .extract(request.request.uri().path(), var_name)
            .map(Path)
            .ok_or(Error::new(
                ErrorKind::InvalidInput,
                format!(
                    "Failed to parse path variable {} in path {}",
                    var_name,
                    request.request.uri().path()
                ),
            ))
    }
}

pub struct Body<T: FromBody>(T);
impl<T: FromBody> Body<T> {
    pub fn inner(self) -> T {
        self.0
    }
}
impl<T: FromBody> AsRef<T> for Body<T> {
    fn as_ref(&self) -> &T {
        &self.0
    }
}
impl<T: FromBody> AsMut<T> for Body<T> {
    fn as_mut(&mut self) -> &mut T {
        &mut self.0
    }
}
#[async_trait]
impl<'a, T: FromBody> FromRequest<'a> for Body<T> {
    async fn from_request(request: &'a mut ServiceRequest, _: &'a str) -> Result<Self, Error> {
        let mut body = request.request.body();
        T::from_body(&mut body).await.map(Body)
    }
}

#[async_trait::async_trait]
pub trait FromBody {
    async fn from_body(body: &mut BodyType) -> Result<Self, Error>
    where
        Self: Sized;
}

#[async_trait::async_trait]
impl FromBody for String {
    async fn from_body(body: &mut BodyType) -> Result<Self, Error> {
        let bytes = body_to_bytes(body).await?;
        Ok(String::from_utf8_lossy(bytes.as_ref()).to_string())
    }
}

pub struct Json<T: for<'a> Deserialize<'a>>(T);
impl<T: for<'a> Deserialize<'a>> Json<T> {
    pub fn inner(self) -> T {
        self.0
    }
}

#[async_trait::async_trait]
impl<T> FromBody for Json<T>
where
    T: for<'a> Deserialize<'a>,
{
    async fn from_body(body: &mut BodyType) -> Result<Self, Error> {
        let bytes = body_to_bytes(body).await?;
        serde_json::from_slice(bytes.as_ref())
            .map_err(|e| {
                Error::new(
                    ErrorKind::InvalidInput,
                    format!("Failed to parse body as JSON: {e:?}"),
                )
            })
            .map(Json)
    }
}

macro_rules! from_body {
    ($int:ident) => {
        #[async_trait::async_trait]
        impl FromBody for $int {
            async fn from_body(body: &mut BodyType) -> Result<Self, Error> {
                let bytes = body_to_bytes(body).await?;
                let as_str = String::from_utf8_lossy(bytes.as_ref());
                as_str.parse().map_err(|e| {
                    Error::new(
                        ErrorKind::InvalidInput,
                        format!("Failed to parse body as $int: {e:?}"),
                    )
                })
            }
        }
    };
}

from_body!(u8);
from_body!(u16);
from_body!(u32);
from_body!(u64);
from_body!(u128);
from_body!(i8);
from_body!(i16);
from_body!(i32);
from_body!(i64);
from_body!(i128);

async fn body_to_bytes(body: &mut BodyType<'_>) -> Result<Bytes, Error> {
    match body {
        BodyType::Sized(b) => b.collect().await.map(|v| v.to_bytes()).map_err(|e| {
            Error::new(
                ErrorKind::InvalidInput,
                format!("Failed to read body: {e:?}"),
            )
        }),
        BodyType::Stream(b) => b.collect().await.map(|v| v.to_bytes()).map_err(|e| {
            Error::new(
                ErrorKind::InvalidInput,
                format!("Failed to read body: {e:?}"),
            )
        }),
    }
}