use std::collections::HashMap;
#[cfg(feature = "async")]
use std::future::Future;
use std::ops::Deref;
use mlua::{
AnyUserData, AsChunk, Chunk, FromLuaMulti, IntoLua, Lua, ObjectLike, Result, Table, Value,
};
use crate::filter::UserFilterWrapper;
use crate::{EventSub, Proxy, UserFilter};
#[derive(Clone)]
pub struct Core<'lua> {
lua: &'lua Lua,
class: Table,
}
#[derive(Debug, Copy, Clone)]
pub struct Time {
pub sec: u64,
pub usec: u64,
}
#[derive(Debug, Copy, Clone)]
pub enum Action {
TcpReq,
TcpRes,
HttpReq,
HttpRes,
HttpAfterRes,
}
impl Action {
fn as_str(&self) -> &'static str {
match self {
Action::TcpReq => "tcp-req",
Action::TcpRes => "tcp-res",
Action::HttpReq => "http-req",
Action::HttpRes => "http-res",
Action::HttpAfterRes => "http-after-res",
}
}
}
#[derive(Debug, Copy, Clone)]
pub enum ServiceMode {
Tcp,
Http,
}
#[derive(Debug, Copy, Clone)]
pub enum LogLevel {
Emerg,
Alert,
Crit,
Err,
Warning,
Notice,
Info,
Debug,
}
impl<'lua> Core<'lua> {
#[inline]
pub fn new(lua: &'lua Lua) -> Result<Self> {
let class: Table = lua.globals().get("core")?;
Ok(Core { lua, class })
}
#[inline]
pub fn proxies(&self) -> Result<HashMap<String, Proxy>> {
self.class.get("proxies")
}
#[inline]
pub fn backends(&self) -> Result<HashMap<String, Proxy>> {
self.class.get("backends")
}
#[inline]
pub fn frontends(&self) -> Result<HashMap<String, Proxy>> {
self.class.get("frontends")
}
#[inline]
pub fn thread(&self) -> Result<u16> {
self.class.get("thread")
}
#[inline]
pub fn log(&self, level: LogLevel, msg: impl AsRef<str>) -> Result<()> {
let msg = msg.as_ref();
self.class.call_function("log", (level, msg))
}
#[inline]
pub fn add_acl(&self, filename: &str, key: &str) -> Result<()> {
self.class.call_function("add_acl", (filename, key))
}
#[inline]
pub fn del_acl(&self, filename: &str, key: &str) -> Result<()> {
self.class.call_function("del_acl", (filename, key))
}
#[inline]
pub fn del_map(&self, filename: &str, key: &str) -> Result<()> {
self.class.call_function("del_map", (filename, key))
}
#[inline]
pub fn set_map(&self, filename: &str, key: &str, value: &str) -> Result<()> {
self.class.call_function("set_map", (filename, key, value))
}
#[inline]
pub fn get_info(&self) -> Result<Table> {
self.class.call_function("get_info", ())
}
#[inline]
pub fn now(&self) -> Result<Time> {
let time: Table = self.class.call_function("now", ())?;
Ok(Time {
sec: time.get("sec")?,
usec: time.get("usec")?,
})
}
pub fn register_action<F, A>(
&self,
name: &str,
actions: &[Action],
nb_args: usize,
func: F,
) -> Result<()>
where
F: Fn(&Lua, A) -> Result<()> + Send + 'static,
A: FromLuaMulti,
{
let func = self.lua.create_function(func)?;
let actions = actions.iter().map(|act| act.as_str()).collect::<Vec<_>>();
self.class
.call_function("register_action", (name, actions, func, nb_args))
}
pub fn register_async_action<F, A, FR>(
&self,
name: &str,
actions: &[Action],
nb_args: usize,
func: F,
) -> Result<()>
where
F: Fn(A) -> FR + 'static,
A: FromLuaMulti + 'static,
FR: Future<Output = Result<()>> + Send + 'static,
{
let func = crate::r#async::create_async_function(self.lua, func)?;
let actions = actions.iter().map(|act| act.as_str()).collect::<Vec<_>>();
self.class
.call_function("register_action", (name, actions, func, nb_args))
}
pub fn register_lua_action(
&self,
name: &str,
actions: &[&str],
nb_args: usize,
code: impl AsChunk,
) -> Result<()> {
let func = self.lua.load(code).into_function()?;
self.class
.call_function("register_action", (name, actions.to_vec(), func, nb_args))
}
pub fn register_converters<F, A, R>(&self, name: &str, func: F) -> Result<()>
where
F: Fn(&Lua, A) -> Result<R> + Send + 'static,
A: FromLuaMulti,
R: IntoLua,
{
let func = self.lua.create_function(func)?;
self.class
.call_function("register_converters", (name, func))
}
pub fn register_lua_converters(&self, name: &str, code: impl AsChunk) -> Result<()> {
let func = self.lua.load(code).into_function()?;
self.class
.call_function("register_converters", (name, func))
}
pub fn register_fetches<F, A, R>(&self, name: &str, func: F) -> Result<()>
where
F: Fn(&Lua, A) -> Result<R> + Send + 'static,
A: FromLuaMulti,
R: IntoLua,
{
let func = self.lua.create_function(func)?;
self.class.call_function("register_fetches", (name, func))
}
pub fn register_lua_fetches(&self, name: &str, code: impl AsChunk) -> Result<()> {
let func = self.lua.load(code).into_function()?;
self.class.call_function("register_fetches", (name, func))
}
pub fn register_filter<T: UserFilter + 'static>(&self, name: &str) -> Result<()> {
let lua = self.lua;
let func = lua.create_function(|_, (class, args): (Table, Table)| {
class.raw_set("args", args)?;
Ok(class)
});
let filter_class = UserFilterWrapper::<T>::make_class(lua)?;
self.class
.call_function("register_filter", (name, filter_class, func))
}
pub fn register_lua_service(
&self,
name: &str,
mode: ServiceMode,
code: impl AsChunk,
) -> Result<()> {
let func = self.lua.load(code).into_function()?;
let mode = match mode {
ServiceMode::Tcp => "tcp",
ServiceMode::Http => "http",
};
self.class
.call_function("register_service", (name, mode, func))
}
pub fn register_init<F>(&self, func: F) -> Result<()>
where
F: Fn(&Lua) -> Result<()> + Send + 'static,
{
let func = self.lua.create_function(move |lua, ()| func(lua))?;
self.class.call_function("register_init", func)
}
pub fn register_task<F>(&self, func: F) -> Result<()>
where
F: Fn(&Lua) -> Result<()> + Send + 'static,
{
let func = self.lua.create_function(move |lua, ()| func(lua))?;
self.class.call_function("register_task", func)
}
#[cfg(feature = "async")]
pub fn register_async_task<F, FR>(&self, func: F) -> Result<()>
where
F: Fn() -> FR + 'static,
FR: Future<Output = Result<()>> + Send + 'static,
{
let func = crate::r#async::create_async_function(self.lua, move |()| func())?;
self.class.call_function("register_task", func)
}
pub fn register_lua_task(&self, code: impl AsChunk) -> Result<()> {
let func = self.lua.load(code).into_function()?;
self.class.call_function("register_task", func)
}
pub fn register_lua_cli(&self, path: &[&str], usage: &str, code: impl AsChunk) -> Result<()> {
let func = self.lua.load(code).into_function()?;
self.class
.call_function("register_cli", (path, usage, func))
}
#[inline]
pub fn set_nice(&self, nice: i32) -> Result<()> {
self.class.call_function("set_nice", nice)
}
#[inline]
pub fn parse_addr(&self, addr: &str) -> Result<AnyUserData> {
self.class.call_function("parse_addr", addr)
}
#[inline]
pub fn match_addr(&self, addr1: AnyUserData, addr2: AnyUserData) -> Result<bool> {
self.class.call_function("match_addr", (addr1, addr2))
}
pub fn event_sub(&self, event_types: &[&str], code: impl AsChunk) -> Result<EventSub> {
(self.class).call_function("event_sub", (event_types, Chunk::wrap(code)))
}
}
impl Deref for Core<'_> {
type Target = Table;
#[inline]
fn deref(&self) -> &Self::Target {
&self.class
}
}
impl IntoLua for LogLevel {
#[inline]
fn into_lua(self, lua: &Lua) -> Result<Value> {
(match self {
LogLevel::Emerg => 0,
LogLevel::Alert => 1,
LogLevel::Crit => 2,
LogLevel::Err => 3,
LogLevel::Warning => 4,
LogLevel::Notice => 5,
LogLevel::Info => 6,
LogLevel::Debug => 7,
})
.into_lua(lua)
}
}