shors 0.1.11

Transport layer for cartridge + tarantool-module projects.
Documentation
use super::Response;
use crate::transport::http::Request;
use std::collections::HashMap;
use tarantool::tlua;
use tarantool::tlua::AnyLuaValue;

pub trait LuaHttpHandler {
    fn handle(&self, req: Request) -> Response;
    fn method(&self) -> &str;
    fn path(&self) -> &str;
}

/// Http server.
pub struct Server {}

#[allow(clippy::new_without_default)]
impl Server {
    pub fn new() -> Self {
        let lua = tarantool::lua_state();

        lua.exec("
            local function make_json_handler(fn)
                return function(req)
                    local data = req:read()  

                    local status, body = fn(req.method, req.path, req.query, req.headers, req.tstash, req.proto, req.peer, data)
                    
                    return {
                        status = status,
                        body = body,
                        headers = { ['content-type'] = 'application/json; charset=utf8' }
                    }
                end
            end

            function register_handler(route, method, handler)
                local httpd = assert(require('cartridge').service_get('httpd'), 'Failed to get httpd service')
                local metrics = require('metrics')
                httpd:route(
                        { method = method, path = route },
                        metrics.http_middleware.v1(
                            make_json_handler(handler),
                            metrics.http_middleware.get_default_collector()
                        )
                )
            end
        ").unwrap();

        Self {}
    }

    /// Register http route as prepared for serve.
    pub fn register(&self, route: Box<dyn LuaHttpHandler>) {
        let lua = tarantool::lua_state();

        let path = route.path().to_string();
        let method = route.method().to_string();
        let lua_handler = tlua::function8(
            move |method: String,
                  path: String,
                  query: String,
                  headers: HashMap<String, String>,
                  stash: HashMap<String, String>,
                  proto: Vec<i32>,
                  peer: HashMap<String, AnyLuaValue>,
                  body: String| {
                let proto: [i32; 2] = proto.try_into().unwrap_or_default();

                let res = route.handle(Request {
                    method,
                    path,
                    query,
                    headers,
                    stash,
                    body,
                    proto: proto.into(),
                    peer: peer.into(),
                });
                (res.status, res.body)
            },
        );

        lua.get::<tlua::LuaFunction<_>, _>("register_handler")
            .unwrap()
            .call_with_args::<(), _>((path, method, lua_handler))
            .expect("register route fail");
    }
}