feat: Add embed and noembed feature flags for HTTP assets/templates

This commit is contained in:
selfhoster selfhoster 2026-09-08 17:24:01 +02:00
commit 1bbdb04dc9
5 changed files with 88 additions and 9 deletions

46
Cargo.lock generated
View file

@ -125,6 +125,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "2.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
[[package]]
name = "block-buffer"
version = "0.12.1"
@ -369,6 +375,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "http-range-header"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
[[package]]
name = "httparse"
version = "1.10.1"
@ -504,11 +516,13 @@ dependencies = [
"http",
"ldap3_proto",
"minijinja",
"minijinja-embed",
"serde",
"static-serve",
"tokio",
"tokio-util",
"tower",
"tower-http",
"tracing",
"tracing-subscriber",
"uuid",
@ -564,6 +578,12 @@ dependencies = [
"serde",
]
[[package]]
name = "minijinja-embed"
version = "2.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2795289c499a1331f73166ff8b8e0e68fdc81ef0b385eecb0e4de96f1638b66"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@ -964,6 +984,7 @@ version = "1.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
dependencies = [
"bytes",
"libc",
"mio",
"pin-project-lite",
@ -1013,6 +1034,31 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower-http"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c"
dependencies = [
"bitflags",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-body-util",
"http-range-header",
"httpdate",
"mime",
"mime_guess",
"percent-encoding",
"pin-project-lite",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"

View file

@ -13,11 +13,13 @@ futures-util = { version = "0.3.34", features = ["sink"] }
http = { version = "1.5.0", optional = true }
ldap3_proto = "0.8.1"
minijinja = { version = "2.24.0", optional = true }
minijinja-embed = { version = "2.24.0", optional = true }
serde = { version = "1.0.229", features = ["derive"] }
static-serve = { version = "0.6.3", optional = true }
tokio = { version = "1.53.1", features = ["macros", "net", "rt", "time", "sync"] }
tokio-util = { version = "0.7.19", features = ["codec"] }
tower = "0.5.3"
tower-http = { version = "0.7.1", features = ["fs"], optional = true }
tracing = "0.1.44"
tracing-subscriber = "0.3.23"
uuid = { version = "1.26.0", features = ["v4"] }
@ -30,5 +32,12 @@ perf = "deny"
style = "deny"
[features]
default = [ "http" ]
http = ["dep:axum", "dep:axum-extra", "dep:http", "dep:minijinja", "dep:static-serve"]
default = [ "http", "noembed" ]
# Embed assets and templates in binary
embed = [ "dep:minijinja-embed", "dep:static-serve" ]
# Don't embed assets and templates in binary
noembed = [ "dep:tower-http" ]
http = ["dep:axum", "dep:axum-extra", "dep:http", "dep:minijinja"]
[build-dependencies]
minijinja-embed = { version = "2.24.0", optional = true }

4
build.rs Normal file
View file

@ -0,0 +1,4 @@
fn main() {
#[cfg(feature = "embed")]
minijinja_embed::embed_templates!("templates");
}

View file

@ -65,10 +65,12 @@ impl DatabaseInterface for MemoryDatabase {
self.create_user(new_user).await
}
fn list_users(&self, domain: Option<String>) -> impl Future<Output = Result<Vec<User>, BoxedError>> {
fn list_users(
&self,
domain: Option<String>,
) -> impl Future<Output = Result<Vec<User>, BoxedError>> {
let users = if let Some(domain) = domain {
self
.users
self.users
.iter()
.filter(|user| user.domain.as_ref() == Some(&domain))
.cloned()

View file

@ -5,8 +5,13 @@ use axum::routing::{get, post};
use axum::serve::Listener as AxumListener;
use axum_extra::extract::cookie::CookieJar;
use http::StatusCode;
use minijinja::{Environment, context, path_loader};
#[cfg(not(feature = "embed"))]
use minijinja::path_loader;
use minijinja::{Environment, context};
#[cfg(feature = "embed")]
use static_serve::embed_assets;
#[cfg(not(feature = "embed"))]
use tower_http::services::ServeDir;
use crate::db::{Database, DatabaseInterface, Operation};
use crate::listener::{Listener, ListenerKind};
@ -67,6 +72,9 @@ pub struct HttpState<D: DatabaseInterface> {
impl<D: DatabaseInterface> HttpState<D> {
pub fn new(db: Database<D>) -> Self {
let mut templates = Environment::new();
#[cfg(feature = "embed")]
minijinja_embed::load_templates!(&mut templates);
#[cfg(not(feature = "embed"))]
templates.set_loader(path_loader("templates"));
Self {
db,
@ -77,9 +85,19 @@ impl<D: DatabaseInterface> HttpState<D> {
}
pub async fn http_listen<D: DatabaseInterface>(listener: Listener, db: Database<D>) {
embed_assets!("assets");
let app = Router::new()
.nest("/assets", static_router())
#[cfg(all(feature = "embed", feature = "noembed"))]
compile_error!("You cannot have `embed` and `noembed` features enabled at the same time.");
#[cfg(not(any(feature = "embed", feature = "noembed")))]
compile_error!("You must have `embed` or `noembed` feature enabled.");
#[cfg(feature = "embed")]
let app = {
embed_assets!("assets");
Router::new().nest("/assets", static_router())
};
#[cfg(not(feature = "embed"))]
let app = { Router::new().nest_service("/assets", ServeDir::new("assets")) };
let app = app
.route("/", get(home))
.route("/login", get(home))
.route("/login", post(login::post_login))