quectocraft2/src/plugin/plugin.rs

77 lines
2 KiB
Rust
Raw Normal View History

2023-07-26 00:53:51 -04:00
use std::fs::DirEntry;
use log::{debug, Record};
use mlua::{Function, FromLua, Lua, Table, Value};
pub struct Plugin<'lua> {
pub table: Table<'lua>,
pub id: String,
}
impl<'lua> FromLua<'lua> for Plugin<'lua> {
fn from_lua(lua_value: Value<'lua>, lua: &'lua Lua) -> mlua::Result<Self> {
let table = Table::from_lua(lua_value, lua)?;
Ok(Plugin {
id: table.get("id")?,
table,
})
}
}
fn lua_locinfo(lua: &Lua) -> Option<(u32, String)> {
let debug = lua.globals().get::<_, Table>("debug").ok()?;
let getinfo = debug.get::<_, Function>("getinfo").ok()?;
let data = getinfo.call::<_, Table>((2,)).ok()?;
let line = data.get("currentline").ok()?;
let file = data.get("short_src").ok()?;
Some((line, file))
}
fn lua_log(level: log::Level, path: &'static str, msg: String, lua: &Lua) {
let mut record = Record::builder();
record.level(level);
record.target(path);
record.module_path_static(Some(path));
let locinfo = lua_locinfo(lua);
if let Some((line, file)) = &locinfo {
record.line(Some(*line));
record.file(Some(file));
}
log::logger().log(&record.args(format_args!("{}", msg)).build());
}
const LEVELS: [(&str, log::Level); 5] = [
("trace", log::Level::Trace),
("debug", log::Level::Debug),
("info", log::Level::Info),
("warn", log::Level::Warn),
("error", log::Level::Error),
];
impl<'lua> Plugin<'lua> {
pub fn load(entry: &DirEntry, lua: &'lua Lua) -> anyhow::Result<Self> {
let ty = entry.file_type()?;
let mut path = entry.path();
if ty.is_dir() {
path.push("main.lua");
}
let chunk = lua.load(&path);
debug!("evaluating plugin");
let plugin = Self::from_lua(chunk.eval()?, lua)?;
// leak: plugins are only loaded at the beginning of the program
// and the path needs to live forever anyway, so this is fine
let path: &'static str = Box::leak(format!("qcplugin::{}", plugin.id).into_boxed_str());
for (name, level) in LEVELS {
plugin.table.set(name, lua.create_function(move |lua, (msg,): (String,)| {
lua_log(level, path, msg, lua);
Ok(())
})?)?;
}
Ok(plugin)
}
}