quectocraft2/src/plugin/plugin.rs
2023-08-01 00:56:38 -04:00

72 lines
1.9 KiB
Rust

use std::{fs::{DirEntry, self}, io::ErrorKind};
use anyhow::anyhow;
use log::{debug, warn, info};
use mlua::{Lua, Table};
use crate::QC_VERSION;
fn load_plugin<'lua>(entry: &DirEntry, lua: &'lua Lua) -> anyhow::Result<(String, Table<'lua>)> {
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 table: Table = chunk.eval()?;
let id = table.get("id")
.map_err(|e| anyhow!("could not get plugin id: {e}"))?;
if let Ok(qc_ver) = table.get::<_, String>("server_version") {
debug!("checking plugin version");
let req = semver::VersionReq::parse(&qc_ver)?;
if !req.matches(&semver::Version::parse(QC_VERSION).unwrap()) {
return Err(anyhow!("incompatible with quectocraft version {QC_VERSION}: expected {req}"));
}
} else {
warn!("plugin '{id}' is missing a version reqirement");
}
Ok((id, table))
}
pub fn load_plugins(lua: &Lua) -> mlua::Result<Table> {
let plugins = lua.create_table()?;
debug!("loading plugins");
let entries = match fs::read_dir("./plugins") {
Ok(n) => n,
Err(e) if e.kind() == ErrorKind::NotFound => {
warn!("plugins directory does not exist, creating");
if let Err(e) = fs::create_dir("./plugins") {
warn!("failed to create plugins directory: {e}");
}
return Ok(plugins)
},
Err(e) => {
warn!("failed to load plugins: {e}");
return Ok(plugins)
}
};
for entry in entries {
let entry = match entry {
Ok(e) => e,
Err(e) => {
warn!("error reading entry: {e}");
continue
}
};
let path = entry.path();
let spath = path.to_str().unwrap_or("<non-unicode path>");
debug!("loading plugin at {spath}");
match load_plugin(&entry, lua) {
Ok((id, table)) => {
info!("loaded plugin {}", id);
plugins.set(id, table)?;
}
Err(e) => warn!("error loading plugin at {spath}: {e}"),
}
}
Ok(plugins)
}