1use std::collections::HashMap;
2#[cfg(feature = "async")]
3use std::future::Future;
4use std::ops::Deref;
5
6use mlua::{AnyUserData, AsChunk, FromLuaMulti, IntoLua, Lua, Result, Table, TableExt, Value};
7
8use crate::filter::UserFilterWrapper;
9use crate::{Proxy, UserFilter};
10
11#[derive(Clone)]
13pub struct Core<'lua> {
14 lua: &'lua Lua,
15 class: Table<'lua>,
16}
17
18#[derive(Debug, Copy, Clone)]
19pub struct Time {
20 pub sec: u64,
21 pub usec: u64,
22}
23
24#[derive(Debug, Copy, Clone)]
25pub enum Action {
26 TcpReq,
27 TcpRes,
28 HttpReq,
29 HttpRes,
30 HttpAfterRes,
31}
32
33impl Action {
34 fn as_str(&self) -> &'static str {
35 match self {
36 Action::TcpReq => "tcp-req",
37 Action::TcpRes => "tcp-res",
38 Action::HttpReq => "http-req",
39 Action::HttpRes => "http-res",
40 Action::HttpAfterRes => "http-after-res",
41 }
42 }
43}
44
45#[derive(Debug, Copy, Clone)]
46pub enum ServiceMode {
47 Tcp,
48 Http,
49}
50
51#[derive(Debug, Copy, Clone)]
52pub enum LogLevel {
53 Emerg,
54 Alert,
55 Crit,
56 Err,
57 Warning,
58 Notice,
59 Info,
60 Debug,
61}
62
63impl<'lua> Core<'lua> {
64 #[inline]
66 pub fn new(lua: &'lua Lua) -> Result<Self> {
67 let class: Table = lua.globals().get("core")?;
68 Ok(Core { lua, class })
69 }
70
71 #[inline]
73 pub fn proxies(&self) -> Result<HashMap<String, Proxy<'lua>>> {
74 self.class.get("proxies")
75 }
76
77 #[inline]
79 pub fn backends(&self) -> Result<HashMap<String, Proxy<'lua>>> {
80 self.class.get("backends")
81 }
82
83 #[inline]
85 pub fn frontends(&self) -> Result<HashMap<String, Proxy<'lua>>> {
86 self.class.get("frontends")
87 }
88
89 #[inline]
93 pub fn thread(&self) -> Result<u16> {
94 self.class.get("thread")
95 }
96
97 #[inline]
99 pub fn log(&self, level: LogLevel, msg: impl AsRef<str>) -> Result<()> {
100 let msg = msg.as_ref();
101 self.class.call_function("log", (level, msg))
102 }
103
104 #[inline]
106 pub fn add_acl(&self, filename: &str, key: &str) -> Result<()> {
107 self.class.call_function("add_acl", (filename, key))
108 }
109
110 #[inline]
112 pub fn del_acl(&self, filename: &str, key: &str) -> Result<()> {
113 self.class.call_function("del_acl", (filename, key))
114 }
115
116 #[inline]
119 pub fn del_map(&self, filename: &str, key: &str) -> Result<()> {
120 self.class.call_function("del_map", (filename, key))
121 }
122
123 #[inline]
125 pub fn set_map(&self, filename: &str, key: &str, value: &str) -> Result<()> {
126 self.class.call_function("set_map", (filename, key, value))
127 }
128
129 #[inline]
131 pub fn get_info(&self) -> Result<Vec<String>> {
132 self.class.call_function("get_info", ())
133 }
134
135 #[inline]
139 pub fn now(&self) -> Result<Time> {
140 let time: Table = self.class.call_function("now", ())?;
141 Ok(Time {
142 sec: time.get("sec")?,
143 usec: time.get("usec")?,
144 })
145 }
146
147 pub fn register_action<A, F>(
151 &self,
152 name: &str,
153 actions: &[Action],
154 nb_args: usize,
155 func: F,
156 ) -> Result<()>
157 where
158 A: FromLuaMulti<'lua>,
159 F: Fn(&'lua Lua, A) -> Result<()> + Send + 'static,
160 {
161 let func = self.lua.create_function(func)?;
162 let actions = actions.iter().map(|act| act.as_str()).collect::<Vec<_>>();
163 self.class
164 .call_function("register_action", (name, actions, func, nb_args))
165 }
166
167 pub fn register_async_action<F, A, FR>(
171 &self,
172 name: &str,
173 actions: &[Action],
174 nb_args: usize,
175 func: F,
176 ) -> Result<()>
177 where
178 F: Fn(A) -> FR + 'static,
179 A: FromLuaMulti<'lua> + 'static,
180 FR: Future<Output = Result<()>> + Send + 'static,
181 {
182 let func = crate::r#async::create_async_function(self.lua, func)?;
183 let actions = actions.iter().map(|act| act.as_str()).collect::<Vec<_>>();
184 self.class
185 .call_function("register_action", (name, actions, func, nb_args))
186 }
187
188 pub fn register_lua_action<'a, S>(
192 &self,
193 name: &str,
194 actions: &[&str],
195 nb_args: usize,
196 code: S,
197 ) -> Result<()>
198 where
199 S: AsChunk<'lua, 'a>,
200 {
201 let func = self.lua.load(code).into_function()?;
202 self.class
203 .call_function("register_action", (name, actions.to_vec(), func, nb_args))
204 }
205
206 pub fn register_converters<A, R, F>(&self, name: &str, func: F) -> Result<()>
209 where
210 A: FromLuaMulti<'lua>,
211 R: IntoLua<'lua>,
212 F: Fn(&'lua Lua, A) -> Result<R> + Send + 'static,
213 {
214 let func = self.lua.create_function(func)?;
215 self.class
216 .call_function("register_converters", (name, func))
217 }
218
219 pub fn register_lua_converters<'a, S>(&self, name: &str, code: S) -> Result<()>
223 where
224 S: AsChunk<'lua, 'a>,
225 {
226 let func = self.lua.load(code).into_function()?;
227 self.class
228 .call_function("register_converters", (name, func))
229 }
230
231 pub fn register_fetches<A, R, F>(&self, name: &str, func: F) -> Result<()>
234 where
235 A: FromLuaMulti<'lua>,
236 R: IntoLua<'lua>,
237 F: Fn(&'lua Lua, A) -> Result<R> + Send + 'static,
238 {
239 let func = self.lua.create_function(func)?;
240 self.class.call_function("register_fetches", (name, func))
241 }
242
243 pub fn register_lua_fetches<'a, S>(&self, name: &str, code: S) -> Result<()>
247 where
248 S: AsChunk<'lua, 'a>,
249 {
250 let func = self.lua.load(code).into_function()?;
251 self.class.call_function("register_fetches", (name, func))
252 }
253
254 pub fn register_filter<T: UserFilter + 'static>(&self, name: &str) -> Result<()> {
256 let lua = self.lua;
257 let func = lua.create_function(|_, (class, args): (Table, Table)| {
258 class.raw_set("args", args)?;
259 Ok(class)
260 });
261 let filter_class = UserFilterWrapper::<T>::make_class(lua)?;
262 self.class
263 .call_function("register_filter", (name, filter_class, func))
264 }
265
266 pub fn register_lua_service<'a, S>(&self, name: &str, mode: ServiceMode, code: S) -> Result<()>
269 where
270 S: AsChunk<'lua, 'a>,
271 {
272 let func = self.lua.load(code).into_function()?;
273 let mode = match mode {
274 ServiceMode::Tcp => "tcp",
275 ServiceMode::Http => "http",
276 };
277 self.class
278 .call_function("register_service", (name, mode, func))
279 }
280
281 pub fn register_init<F>(&self, func: F) -> Result<()>
284 where
285 F: Fn(&'lua Lua) -> Result<()> + Send + 'static,
286 {
287 let func = self.lua.create_function(move |lua, ()| func(lua))?;
288 self.class.call_function("register_init", func)
289 }
290
291 pub fn register_task<F>(&self, func: F) -> Result<()>
294 where
295 F: Fn(&'lua Lua) -> Result<()> + Send + 'static,
296 {
297 let func = self.lua.create_function(move |lua, ()| func(lua))?;
298 self.class.call_function("register_task", func)
299 }
300
301 #[cfg(feature = "async")]
303 pub fn register_async_task<F, FR>(&self, func: F) -> Result<()>
304 where
305 F: Fn() -> FR + 'static,
306 FR: Future<Output = Result<()>> + Send + 'static,
307 {
308 let func = crate::r#async::create_async_function(self.lua, move |()| func())?;
309 self.class.call_function("register_task", func)
310 }
311
312 pub fn register_lua_task<'a, S>(&self, code: S) -> Result<()>
316 where
317 S: AsChunk<'lua, 'a>,
318 {
319 let func = self.lua.load(code).into_function()?;
320 self.class.call_function("register_task", func)
321 }
322
323 pub fn register_lua_cli<'a, S>(&self, path: &[&str], usage: &str, code: S) -> Result<()>
325 where
326 S: AsChunk<'lua, 'a>,
327 {
328 let func = self.lua.load(code).into_function()?;
329 self.class
330 .call_function("register_cli", (path, usage, func))
331 }
332
333 #[inline]
335 pub fn set_nice(&self, nice: i32) -> Result<()> {
336 self.class.call_function("set_nice", nice)
337 }
338
339 #[inline]
341 pub fn parse_addr(&self, addr: &str) -> Result<AnyUserData<'lua>> {
342 self.class.call_function("parse_addr", addr)
343 }
344
345 #[inline]
348 pub fn match_addr(&self, addr1: AnyUserData, addr2: AnyUserData) -> Result<bool> {
349 self.class.call_function("match_addr", (addr1, addr2))
350 }
351
352 pub fn event_sub<'a, S>(&self, event_types: &[&str], code: S) -> Result<()>
353 where
354 S: AsChunk<'lua, 'a>,
355 {
356 let func = self.lua.load(code).into_function()?;
357 self.class.call_function("event_sub", (event_types, func))
358 }
359}
360
361impl<'lua> Deref for Core<'lua> {
362 type Target = Table<'lua>;
363
364 #[inline]
365 fn deref(&self) -> &Self::Target {
366 &self.class
367 }
368}
369
370impl<'lua> IntoLua<'lua> for LogLevel {
371 #[inline]
372 fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
373 (match self {
374 LogLevel::Emerg => 0,
375 LogLevel::Alert => 1,
376 LogLevel::Crit => 2,
377 LogLevel::Err => 3,
378 LogLevel::Warning => 4,
379 LogLevel::Notice => 5,
380 LogLevel::Info => 6,
381 LogLevel::Debug => 7,
382 })
383 .into_lua(lua)
384 }
385}