1use std::collections::HashMap;
2#[cfg(feature = "async")]
3use std::future::Future;
4use std::ops::Deref;
5
6use mlua::{
7 AnyUserData, AsChunk, Chunk, FromLuaMulti, IntoLua, Lua, ObjectLike, Result, Table, Value,
8};
9
10use crate::filter::UserFilterWrapper;
11use crate::{EventSub, Proxy, UserFilter};
12
13#[derive(Clone)]
17pub struct Core<'lua> {
18 lua: &'lua Lua,
19 class: Table,
20}
21
22#[derive(Debug, Copy, Clone)]
23pub struct Time {
24 pub sec: u64,
25 pub usec: u64,
26}
27
28#[derive(Debug, Copy, Clone)]
29pub enum Action {
30 TcpReq,
31 TcpRes,
32 HttpReq,
33 HttpRes,
34 HttpAfterRes,
35}
36
37impl Action {
38 fn as_str(&self) -> &'static str {
39 match self {
40 Action::TcpReq => "tcp-req",
41 Action::TcpRes => "tcp-res",
42 Action::HttpReq => "http-req",
43 Action::HttpRes => "http-res",
44 Action::HttpAfterRes => "http-after-res",
45 }
46 }
47}
48
49#[derive(Debug, Copy, Clone)]
50pub enum ServiceMode {
51 Tcp,
52 Http,
53}
54
55#[derive(Debug, Copy, Clone)]
56pub enum LogLevel {
57 Emerg,
58 Alert,
59 Crit,
60 Err,
61 Warning,
62 Notice,
63 Info,
64 Debug,
65}
66
67impl<'lua> Core<'lua> {
68 #[inline]
70 pub fn new(lua: &'lua Lua) -> Result<Self> {
71 let class: Table = lua.globals().get("core")?;
72 Ok(Core { lua, class })
73 }
74
75 #[inline]
77 pub fn proxies(&self) -> Result<HashMap<String, Proxy>> {
78 self.class.get("proxies")
79 }
80
81 #[inline]
83 pub fn backends(&self) -> Result<HashMap<String, Proxy>> {
84 self.class.get("backends")
85 }
86
87 #[inline]
89 pub fn frontends(&self) -> Result<HashMap<String, Proxy>> {
90 self.class.get("frontends")
91 }
92
93 #[inline]
97 pub fn thread(&self) -> Result<u16> {
98 self.class.get("thread")
99 }
100
101 #[inline]
103 pub fn log(&self, level: LogLevel, msg: impl AsRef<str>) -> Result<()> {
104 let msg = msg.as_ref();
105 self.class.call_function("log", (level, msg))
106 }
107
108 #[inline]
110 pub fn add_acl(&self, filename: &str, key: &str) -> Result<()> {
111 self.class.call_function("add_acl", (filename, key))
112 }
113
114 #[inline]
116 pub fn del_acl(&self, filename: &str, key: &str) -> Result<()> {
117 self.class.call_function("del_acl", (filename, key))
118 }
119
120 #[inline]
123 pub fn del_map(&self, filename: &str, key: &str) -> Result<()> {
124 self.class.call_function("del_map", (filename, key))
125 }
126
127 #[inline]
129 pub fn set_map(&self, filename: &str, key: &str, value: &str) -> Result<()> {
130 self.class.call_function("set_map", (filename, key, value))
131 }
132
133 #[inline]
135 pub fn get_info(&self) -> Result<Table> {
136 self.class.call_function("get_info", ())
137 }
138
139 #[inline]
143 pub fn now(&self) -> Result<Time> {
144 let time: Table = self.class.call_function("now", ())?;
145 Ok(Time {
146 sec: time.get("sec")?,
147 usec: time.get("usec")?,
148 })
149 }
150
151 pub fn register_action<F, A>(
155 &self,
156 name: &str,
157 actions: &[Action],
158 nb_args: usize,
159 func: F,
160 ) -> Result<()>
161 where
162 F: Fn(&Lua, A) -> Result<()> + Send + 'static,
163 A: FromLuaMulti,
164 {
165 let func = self.lua.create_function(func)?;
166 let actions = actions.iter().map(|act| act.as_str()).collect::<Vec<_>>();
167 self.class
168 .call_function("register_action", (name, actions, func, nb_args))
169 }
170
171 pub fn register_async_action<F, A, FR>(
175 &self,
176 name: &str,
177 actions: &[Action],
178 nb_args: usize,
179 func: F,
180 ) -> Result<()>
181 where
182 F: Fn(A) -> FR + 'static,
183 A: FromLuaMulti + 'static,
184 FR: Future<Output = Result<()>> + Send + 'static,
185 {
186 let func = crate::r#async::create_async_function(self.lua, func)?;
187 let actions = actions.iter().map(|act| act.as_str()).collect::<Vec<_>>();
188 self.class
189 .call_function("register_action", (name, actions, func, nb_args))
190 }
191
192 pub fn register_lua_action(
196 &self,
197 name: &str,
198 actions: &[&str],
199 nb_args: usize,
200 code: impl AsChunk,
201 ) -> Result<()> {
202 let func = self.lua.load(code).into_function()?;
203 self.class
204 .call_function("register_action", (name, actions.to_vec(), func, nb_args))
205 }
206
207 pub fn register_converters<F, A, R>(&self, name: &str, func: F) -> Result<()>
210 where
211 F: Fn(&Lua, A) -> Result<R> + Send + 'static,
212 A: FromLuaMulti,
213 R: IntoLua,
214 {
215 let func = self.lua.create_function(func)?;
216 self.class
217 .call_function("register_converters", (name, func))
218 }
219
220 pub fn register_lua_converters(&self, name: &str, code: impl AsChunk) -> Result<()> {
224 let func = self.lua.load(code).into_function()?;
225 self.class
226 .call_function("register_converters", (name, func))
227 }
228
229 pub fn register_fetches<F, A, R>(&self, name: &str, func: F) -> Result<()>
232 where
233 F: Fn(&Lua, A) -> Result<R> + Send + 'static,
234 A: FromLuaMulti,
235 R: IntoLua,
236 {
237 let func = self.lua.create_function(func)?;
238 self.class.call_function("register_fetches", (name, func))
239 }
240
241 pub fn register_lua_fetches(&self, name: &str, code: impl AsChunk) -> Result<()> {
245 let func = self.lua.load(code).into_function()?;
246 self.class.call_function("register_fetches", (name, func))
247 }
248
249 pub fn register_filter<T: UserFilter + 'static>(&self, name: &str) -> Result<()> {
251 let lua = self.lua;
252 let func = lua.create_function(|_, (class, args): (Table, Table)| {
253 class.raw_set("args", args)?;
254 Ok(class)
255 });
256 let filter_class = UserFilterWrapper::<T>::make_class(lua)?;
257 self.class
258 .call_function("register_filter", (name, filter_class, func))
259 }
260
261 pub fn register_lua_service(
264 &self,
265 name: &str,
266 mode: ServiceMode,
267 code: impl AsChunk,
268 ) -> Result<()> {
269 let func = self.lua.load(code).into_function()?;
270 let mode = match mode {
271 ServiceMode::Tcp => "tcp",
272 ServiceMode::Http => "http",
273 };
274 self.class
275 .call_function("register_service", (name, mode, func))
276 }
277
278 pub fn register_init<F>(&self, func: F) -> Result<()>
281 where
282 F: Fn(&Lua) -> Result<()> + Send + 'static,
283 {
284 let func = self.lua.create_function(move |lua, ()| func(lua))?;
285 self.class.call_function("register_init", func)
286 }
287
288 pub fn register_task<F>(&self, func: F) -> Result<()>
291 where
292 F: Fn(&Lua) -> Result<()> + Send + 'static,
293 {
294 let func = self.lua.create_function(move |lua, ()| func(lua))?;
295 self.class.call_function("register_task", func)
296 }
297
298 #[cfg(feature = "async")]
300 pub fn register_async_task<F, FR>(&self, func: F) -> Result<()>
301 where
302 F: Fn() -> FR + 'static,
303 FR: Future<Output = Result<()>> + Send + 'static,
304 {
305 let func = crate::r#async::create_async_function(self.lua, move |()| func())?;
306 self.class.call_function("register_task", func)
307 }
308
309 pub fn register_lua_task(&self, code: impl AsChunk) -> Result<()> {
313 let func = self.lua.load(code).into_function()?;
314 self.class.call_function("register_task", func)
315 }
316
317 pub fn register_lua_cli(&self, path: &[&str], usage: &str, code: impl AsChunk) -> Result<()> {
319 let func = self.lua.load(code).into_function()?;
320 self.class
321 .call_function("register_cli", (path, usage, func))
322 }
323
324 #[inline]
326 pub fn set_nice(&self, nice: i32) -> Result<()> {
327 self.class.call_function("set_nice", nice)
328 }
329
330 #[inline]
332 pub fn parse_addr(&self, addr: &str) -> Result<AnyUserData> {
333 self.class.call_function("parse_addr", addr)
334 }
335
336 #[inline]
339 pub fn match_addr(&self, addr1: AnyUserData, addr2: AnyUserData) -> Result<bool> {
340 self.class.call_function("match_addr", (addr1, addr2))
341 }
342
343 pub fn event_sub(&self, event_types: &[&str], code: impl AsChunk) -> Result<EventSub> {
345 (self.class).call_function("event_sub", (event_types, Chunk::wrap(code)))
346 }
347}
348
349impl Deref for Core<'_> {
350 type Target = Table;
351
352 #[inline]
353 fn deref(&self) -> &Self::Target {
354 &self.class
355 }
356}
357
358impl IntoLua for LogLevel {
359 #[inline]
360 fn into_lua(self, lua: &Lua) -> Result<Value> {
361 (match self {
362 LogLevel::Emerg => 0,
363 LogLevel::Alert => 1,
364 LogLevel::Crit => 2,
365 LogLevel::Err => 3,
366 LogLevel::Warning => 4,
367 LogLevel::Notice => 5,
368 LogLevel::Info => 6,
369 LogLevel::Debug => 7,
370 })
371 .into_lua(lua)
372 }
373}