~aleteoryx/lfm_embed

ca7c46e535ac60a976a8c60477fa9424c46b6e3f — alyx 8 months ago d7727c2
lua loading
4 files changed, 66 insertions(+), 8 deletions(-)

M Cargo.toml
M src/config.rs
M src/theming/hbs.rs
M src/theming/lua.rs
M Cargo.toml => Cargo.toml +1 -1
@@ 16,7 16,7 @@ env_logger = "0.10.0"
handlebars = { version = "4.3.7", features = ["dir_source"] }
http = "0.2.9"
log = "0.4.19"
mlua = { version = "0.9.6", features = ["serialize", "send", "luau", "async"] }
mlua = { version = "0.9.7", features = ["serialize", "send", "luau", "async", "unstable"] }
reqwest = { version = "0.11.18", features = ["gzip", "deflate", "brotli", "json"] }
serde = { version = "1.0.183", features = ["derive", "rc", "alloc"] }
serde_json = "1.0.104"

M src/config.rs => src/config.rs +4 -2
@@ 21,7 21,8 @@ pub struct Config {

  pub(crate) default_theme: Arc<str>,
  pub(crate) theme_dir: Option<Arc<str>>,
  pub(crate) theme_ext: Arc<str>,
  pub(crate) theme_ext_hbs: Arc<str>,
  pub(crate) theme_ext_lua: Arc<str>,
  pub(crate) theme_debug: bool,

  pub(crate) allowlist: BTreeSet<String>,


@@ 45,7 46,8 @@ impl Config {

      default_theme: var("LFME_THEME_DEFAULT").map(Into::into).unwrap_or_else(|_| "plain".into()),
      theme_dir: var("LFME_THEME_DIR").ok().map(Into::into),
      theme_ext: var("LFME_THEME_EXT").unwrap_or_else(|_| ".hbs".into()).into(),
      theme_ext_hbs: var("LFME_THEME_EXT_HBS").unwrap_or_else(|_| ".hbs".into()).into(),
      theme_ext_lua: var("LFME_THEME_EXT_LUA").unwrap_or_else(|_| ".lua".into()).into(),
      theme_debug: var("LFME_THEME_DEV").map(|h| &h == "1").unwrap_or(false),

      allowlist: var("LFME_WHITELIST").or_else(|_| var("LFME_ALLOWLIST")).ok().map(|w| w.split(',').map(|s| s.trim().to_string()).collect()).unwrap_or_default(),

M src/theming/hbs.rs => src/theming/hbs.rs +1 -1
@@ 22,7 22,7 @@ static HANDLEBARS: LazyLock<Handlebars> = LazyLock::new(|| {

  if let Some(themes_dir) = CONFIG.theme_dir.as_ref() {
    log::info!("Registering theme dir `{themes_dir}`");
    hb.register_templates_directory(&CONFIG.theme_ext, themes_dir.as_ref()).unwrap();
    hb.register_templates_directory(&CONFIG.theme_ext_hbs, themes_dir.as_ref()).unwrap();
  }

  hb

M src/theming/lua.rs => src/theming/lua.rs +60 -4
@@ 1,13 1,16 @@
// SPDX-License-Identifier: AGPL-3.0-only
use std::sync::LazyLock;
use std::collections::BTreeMap;
use std::ops::Deref;
use std::path::Path;

use tokio::sync::Mutex;
use mlua::*;
use mlua::{Lua, Compiler, StdLib, Value, LuaOptions};
use http::StatusCode;

use crate::CONFIG;

static INTERNAL_THEMES: &[(&str, &str)] = &[];

static LUA: LazyLock<Mutex<Lua>> = LazyLock::new(|| {
  let stdlib = StdLib::TABLE | StdLib::STRING | StdLib::UTF8 | StdLib::BIT | StdLib::MATH;
  let lua = Lua::new_with(stdlib, LuaOptions::new().thread_pool_size(2)).expect("lua initialization");


@@ 23,13 26,66 @@ static LUA: LazyLock<Mutex<Lua>> = LazyLock::new(|| {
    .set_compiler(Compiler::new().set_optimization_level(2).set_debug_level(1))
    .eval()
    .expect("expect.lua loading");
  lua.globals().set("expect", expect);
  lua.globals().set("expect", expect).unwrap();

  let html: Value = lua.load(include_str!("lua-lib/html.lua"))
    .set_compiler(Compiler::new().set_optimization_level(2).set_debug_level(1))
    .eval()
    .expect("html.lua loading");
  lua.globals().set("html", html);
  lua.globals().set("html", html).unwrap();

  let themes = lua.create_table().expect("creating themes table");

  for (k, v) in INTERNAL_THEMES {
    let _ = themes.set(*k, lua.load(*v).into_function().expect("loading internal theme"));
  }

  if let Some(theme_dir) = CONFIG.theme_dir.as_ref() {
    for (k, v) in walk_dir(theme_dir.as_ref().as_ref()).expect("walking theme dir") {
      let _ = themes.set(k, lua.load(v).into_function().expect("loading internal theme"));
    }
  }

  let _ = lua.globals().set("__themes", themes).unwrap();

  lua.globals().set_readonly(true);

  Mutex::new(lua)
});

fn walk_dir(path: &Path) -> std::io::Result<Vec<(String, String)>> {
  use std::fs;

  let mut path_bits = vec![];
  let mut dir_readers = vec![fs::read_dir(path)?];

  let mut ret = vec![];

  while let Some(r) = dir_readers.iter_mut().last() {
    if let Some(ent) = r.next() {
      let ent = ent?;
      let name = ent.file_name().into_string().expect("why do you have such FUCKED UP FILE PATHS");
      let ty = ent.file_type()?;
      if ty.is_file() && name.ends_with(CONFIG.theme_ext_lua.as_ref()) {
        ret.push((path_bits.join("") + &name, fs::read_to_string(ent.path())?));
      }
      else if ty.is_dir() {
        path_bits.push(name);
        dir_readers.push(fs::read_dir(ent.path())?);
      }
    }
    else {
      dir_readers.pop();
    }
  }

  Ok(ret)
}

pub fn touch() {
  let _ = LUA.deref();
}

pub fn render_theme(name: &str, ctx: &crate::ctx::Ctx) -> Option<Result<String, StatusCode>> {
  return None
}