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;
}
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 {}
}
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");
}
}