mrps 0.1.1

Mini reverse proxy server
use minijinja::Value;
use reqwest::{Method, Url};
use serde_derive::Serialize;
use std::collections::HashMap;
use tokio::task::block_in_place;
use reqwest::blocking::{Client, Response};
use crate::debug::debug;

#[derive(Serialize)]
struct Res {
    status: u16,
    headers: HashMap<String, String>,
    body: Vec<u8>
}

impl Res {
    fn new(response: Response) -> Value {
        let status = response.status().as_u16();
        let mut headers = HashMap::new();
        for key in response.headers().keys() {
            if let Some(value) = response.headers().get(key) {
                if let Ok(value) = value.to_str() {
                    headers.insert(key.to_string(), value.to_string());
                }
            }
        }

        match response.bytes() {
            Ok(body) => Value::from_serialize(Res {
                status,
                headers,
                body: body.to_vec()
            }),
            Err(_) => Value::from_serialize(Res {
                status,
                headers,
                body: Vec::new()
            })
        }
    }

    fn err(message: String) -> Value {
        Value::from_serialize(Res {
            status: 400,
            headers: HashMap::new(),
            body: message.as_bytes().to_vec()
        })
    }
}

fn fetch(method: &str, url: &str, body: Option<&Vec<u8>>) -> Value {
    let method: Method = match method.parse() {
        Ok(method) => method,
        Err(err) => {
            return Res::err(format!("Invalid method!\n{:#?}", err));
        }
    };

    let url: Url = match url.parse() {
        Ok(url) => url,
        Err(err) => {
            return Res::err(format!("Invalid URL!\n{:#?}", err));
        }
    };

    let m = method.as_str().to_string();
    let p = url.to_string();
    let mut request = Client::new().request(method, url);
    if let Some(body) = body {
        request = request.body(body.to_vec());
    }

    debug(&m, &p, None, "");
    block_in_place(move || {
        match request.send() {
            Ok(response) => {
                debug(&m, &p, Some(200), "");
                Res::new(response)
            },
            Err(err) => {
                let error = err.to_string();
                debug(&m, &p, Some(500), &error);
                Res::err(format!("Request fail!\n{}", &error))
            }
        }
    })
}

pub fn get(url: &str) -> Value {
    fetch("GET", url, None)
}

pub fn post(url: &str, body: &Vec<u8>) -> Value {
    fetch("POST", url, Some(body))
}

pub fn put(url: &str, body: &Vec<u8>) -> Value {
    fetch("PUT", url, Some(body))
}

pub fn patch(url: &str, body: &Vec<u8>) -> Value {
    fetch("PATCH", url, Some(body))
}

pub fn head(url: &str) -> Value {
    fetch("HEAD", url, None)
}

pub fn options(url: &str) -> Value {
    fetch("OPTIONS", url, None)
}

pub fn delete(url: &str) -> Value {
    fetch("DELETE", url, None)
}