diff options
-rw-r--r-- | src/cache.rs | 5 | ||||
-rw-r--r-- | src/cache/font.rs | 4 | ||||
-rw-r--r-- | src/cache/user.rs | 4 | ||||
-rw-r--r-- | src/config.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 5 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/theming.rs | 5 | ||||
-rw-r--r-- | src/theming/hbs.rs | 6 | ||||
-rw-r--r-- | src/theming/lua.rs | 45 |
9 files changed, 67 insertions, 13 deletions
diff --git a/src/cache.rs b/src/cache.rs index 4ef77dc..0c254cb 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -82,3 +82,8 @@ where pub type CacheFuture<Output> = Pin<Box<(dyn Future<Output = Result<Output, (StatusCode, &'static str)>> + Send + Sync)>>; pub type CacheGetter<Output> = fn(&String) -> CacheFuture<Output>; pub type Cache<Output> = Arc<RwLock<AsyncCache<String, Output, CacheGetter<Output>>>>; + +pub fn touch() { + user::touch(); + font::touch(); +} diff --git a/src/cache/font.rs b/src/cache/font.rs index 5be2196..a238a87 100644 --- a/src/cache/font.rs +++ b/src/cache/font.rs @@ -57,3 +57,7 @@ static FONT_CACHE: LazyLock<FontCache> = LazyLock::new(|| { pub async fn get_fontinfo(font: &String) -> Result<Arc<str>, (StatusCode, &'static str)> { FONT_CACHE.write().await.get_owned(font).await } + +pub fn touch() { + LazyLock::force(&FONT_CACHE); +} diff --git a/src/cache/user.rs b/src/cache/user.rs index e228cc2..8d6bf64 100644 --- a/src/cache/user.rs +++ b/src/cache/user.rs @@ -101,3 +101,7 @@ pub async fn get_userinfo(user: &String) -> (Result<Arc<(User, Track, TrackStub) } } } + +pub fn touch() { + LazyLock::force(&ALLOWLIST); +} diff --git a/src/config.rs b/src/config.rs index 008eb7a..917646e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,7 +23,7 @@ pub struct Config { pub(crate) theme_dir: Option<Arc<str>>, pub(crate) theme_ext_hbs: Arc<str>, pub(crate) theme_ext_lua: Arc<str>, - pub(crate) theme_debug: bool, + pub(crate) theme_dev: bool, pub(crate) allowlist: BTreeSet<String>, pub(crate) allowlist_mode: String, @@ -48,7 +48,7 @@ impl Config { theme_dir: var("LFME_THEME_DIR").ok().map(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), + theme_dev: 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(), allowlist_mode: var("LFME_WHITELIST_MODE").or_else(|_| var("LFME_ALLOWLIST_MODE")).map(|m| m.to_ascii_lowercase()).unwrap_or_else(|_| "open".into()), @@ -10,3 +10,8 @@ pub mod ctx; pub mod theming; pub use config::CONFIG; + +pub fn touch() { + cache::touch(); + theming::touch(); +} diff --git a/src/main.rs b/src/main.rs index 57975db..6b1aac0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,6 +45,8 @@ async fn main() { .unwrap_or(env_logger::Target::Stderr) ).init(); + lfm_embed::touch(); + let user = warp::path!("user" / String) .and(warp::query::<UserQuery>()) .then(|s, q: UserQuery| async move { diff --git a/src/theming.rs b/src/theming.rs index 1d7b1f2..6e5b3ba 100644 --- a/src/theming.rs +++ b/src/theming.rs @@ -24,3 +24,8 @@ pub fn render_theme(name: Option<&str>, ctx: &crate::ctx::Ctx) -> (String, Resul (theme.into(), res) } + +pub fn touch() { + hbs::touch(); + lua::touch(); +} diff --git a/src/theming/hbs.rs b/src/theming/hbs.rs index 67a2ae4..398715a 100644 --- a/src/theming/hbs.rs +++ b/src/theming/hbs.rs @@ -18,7 +18,7 @@ static HANDLEBARS: LazyLock<Handlebars> = LazyLock::new(|| { log::info!("Registering internal handlebars theme `{key}`"); hb.register_template_string(key, fulltext).unwrap(); } - hb.set_dev_mode(CONFIG.theme_debug); + hb.set_dev_mode(CONFIG.theme_dev); if let Some(themes_dir) = CONFIG.theme_dir.as_ref() { log::info!("Registering handlebars theme dir `{themes_dir}` with extension `{}`.", CONFIG.theme_ext_hbs); @@ -34,3 +34,7 @@ pub fn render_theme(name: &str, ctx: &crate::ctx::Ctx) -> Option<Result<String, let render = templ.renders(&HANDLEBARS, &ctx, &mut RenderContext::new(Some(&name.into()))).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR); Some(render) } + +pub fn touch() { + LazyLock::force(&HANDLEBARS); +} diff --git a/src/theming/lua.rs b/src/theming/lua.rs index 6bd6989..0699f09 100644 --- a/src/theming/lua.rs +++ b/src/theming/lua.rs @@ -18,7 +18,7 @@ static LUA: LazyLock<Mutex<Lua>> = LazyLock::new(|| { lua.sandbox(true).expect("lua initialization"); lua.set_compiler( - if CONFIG.theme_debug { Compiler::new().set_optimization_level(0).set_debug_level(2) } + if CONFIG.theme_dev { Compiler::new().set_optimization_level(0).set_debug_level(2) } else { Compiler::new().set_optimization_level(2).set_debug_level(1) } ); @@ -38,14 +38,19 @@ static LUA: LazyLock<Mutex<Lua>> = LazyLock::new(|| { for (k, v) in INTERNAL_THEMES { log::info!("Registering compiled lua theme `{k}`."); - let _ = themes.set(*k, lua.load(*v).into_function().expect("loading internal theme")); + let _ = themes.set(*k, lua.load(*v).eval::<Value>().expect("loading internal theme")); } if let Some(theme_dir) = CONFIG.theme_dir.as_ref() { - log::info!("Registering lua theme dir `{theme_dir}` with extension `{}`.", CONFIG.theme_ext_lua); - for (k, v) in walk_dir(theme_dir.as_ref().as_ref()).expect("walking theme dir") { - log::info!("Registering runtime lua theme `{k}`."); - let _ = themes.set(k, lua.load(v).eval::<Value>().expect("loading internal theme")); + if !CONFIG.theme_dev { + log::info!("Registering lua theme dir `{theme_dir}` with extension `{}`.", CONFIG.theme_ext_lua); + for (k, v) in walk_dir(theme_dir.as_ref().as_ref()).expect("walking theme dir") { + log::info!("Registering runtime lua theme `{k}`."); + let _ = themes.set(k, lua.load(v).eval::<Value>().expect("loading external theme")); + } + } + else { + log::info!("Ready to dev-load lua themes from `{theme_dir}` with extension `{}`.", CONFIG.theme_ext_lua); } } @@ -86,13 +91,29 @@ fn walk_dir(path: &Path) -> std::io::Result<Vec<(String, String)>> { } pub fn render_theme(name: &str, ctx: &crate::ctx::Ctx) -> Option<Result<String, StatusCode>> { + if name == ".." || name.starts_with("../") || name.ends_with("/..") || name.contains("/../") { + return Some(Err(StatusCode::BAD_REQUEST)) + } + LUA.clear_poison(); let lua = LUA.lock().expect("FIXME: Mutex poisoning race condition."); let themes: Table = lua.globals().get("__themes").unwrap(); - let Ok(Value::Function(theme)) = themes.get(name) - else { - return None; - }; + let theme; + match themes.get(name) { + Ok(Value::Function(themefn)) => { theme = themefn; }, + Ok(Value::Nil) if !CONFIG.theme_dev || CONFIG.theme_dir.is_none() => { return None; }, + Ok(Value::Nil) => { + let code = fs::read_to_string(CONFIG.theme_dir.as_ref().unwrap().to_string() + "/" + name + &CONFIG.theme_ext_lua).ok()?; + let res = lua.load(code).eval::<Value>(); + match res { + Ok(Value::Function(themefn)) => { theme = themefn; }, + Ok(v) => { log::error!("Got `{v:?}` instead of Function when dev-loading `{name}`."); return Some(Err(StatusCode::INTERNAL_SERVER_ERROR)); }, + Err(e) => { log::error!("Error dev-loading `{name}`: {e}"); return Some(Err(StatusCode::INTERNAL_SERVER_ERROR)); }, + } + }, + Ok(v) => { log::error!("Got `{v:?}` instead of Function when loading `{name}`."); return Some(Err(StatusCode::INTERNAL_SERVER_ERROR)); } + Err(e) => { log::error!("Error loading `{name}`: {e}"); return Some(Err(StatusCode::INTERNAL_SERVER_ERROR)); }, //TODO: gate behind flag + } let ctx = match lua.to_value(ctx) { Ok(ok) => ok, @@ -104,3 +125,7 @@ pub fn render_theme(name: &str, ctx: &crate::ctx::Ctx) -> Option<Result<String, Some(theme.call((ctx,)).map_err(|e| { log::error!("Lua theme execution error: {e}"); StatusCode::INTERNAL_SERVER_ERROR })) } + +pub fn touch() { + LazyLock::force(&LUA); +} |