From da6fb1c3c81b2ec8ebec4825aef9eec4ee26c396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20Eng=C3=A9libert?= Date: Sat, 14 Mar 2026 10:50:03 +0100 Subject: [PATCH] Config TOML, CLI options --- Cargo.lock | 56 ++++++++++++++++++++++++++++++++++++++ Cargo.toml | 8 ++++++ example_config.toml | 31 +++++++++++++++++++++ src/config.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 30 +++++++++++++++++++-- 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 example_config.toml diff --git a/Cargo.lock b/Cargo.lock index d8e00dd..11d0aea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,27 @@ version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +[[package]] +name = "argp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7409aa6f1dd8464eac2e56cf538e1e5f7f79678caa32f198d214a3db8d5075c1" +dependencies = [ + "argp_derive", +] + +[[package]] +name = "argp_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9b949411282939e3f7d8923127e3f18aa474b46da4e8bb0ddf2cb8c81f963a" +dependencies = [ + "proc-macro2", + "pulldown-cmark", + "quote", + "syn", +] + [[package]] name = "askama" version = "0.12.1" @@ -259,8 +280,10 @@ checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" name = "blindforge" version = "0.1.0" dependencies = [ + "argp", "askama", "base64-turbo", + "boml", "form_urlencoded", "giallo", "log", @@ -299,6 +322,12 @@ dependencies = [ "piper", ] +[[package]] +name = "boml" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96d68a303a5dd009292d8fea60bf27916d734d6841b53a53c685ad80182526d" + [[package]] name = "cc" version = "1.2.56" @@ -627,6 +656,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.3.4" @@ -1208,6 +1246,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags", + "getopts", + "memchr", + "unicase", +] + [[package]] name = "quote" version = "1.0.45" @@ -1905,6 +1955,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + [[package]] name = "unicode-xid" version = "0.2.6" diff --git a/Cargo.toml b/Cargo.toml index 08fc731..1f41a67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,17 @@ version = "0.1.0" edition = "2024" [dependencies] +# CLI options +argp = "0.4.0" +# Templates askama = "0.12.1" base64-turbo = "0.1.3" +# TOML parser +boml = "1.0.2" #flate2 = "1.1.8" +# request parsing form_urlencoded = "1.2.2" +# Code highlight giallo = { version = "0.3.1", features = ["dump"] } log = "0.4.29" rand = "0.9.2" @@ -15,6 +22,7 @@ serde = { version = "1.0.228", features = ["derive"] } sha2 = "0.10.9" simplelog = "0.12.2" #tar = "0.4.44" +# Web server trillium = "0.2.20" trillium-askama = "0.3.2" trillium-caching-headers = "0.2.3" diff --git a/example_config.toml b/example_config.toml new file mode 100644 index 0000000..47f7b60 --- /dev/null +++ b/example_config.toml @@ -0,0 +1,31 @@ +# This is an example config file for blindforge. +# It contains all default values in comments. + +# The server will listen to this address. +#listen_host = "127.0.0.1" + +# The server will listen to this port. +#listen_port = 44617 + +# Server's permanent data will be stored in this directory. +#data_dir = "/var/lib/blindforge" +data_dir = "/dev/shm/blindforge" + +# Client will connect to the Git forge API using this User-Agent. +#api_client_user_agent = "Blindforge" + +# Client will download at most this number of pages. +#api_client_max_page = 32 + +# Maximum number of entries (files and directories) in a repository. +#max_entries = 1024 + +# Bigger files in repositories will be omitted. (bytes) +# Default: 8 MB +#max_file_size = 8388608 + +# Files with a longer path in a repository will be omitted. (characters) +#max_file_path_len = 8192 + +# Maximum length of an URL for the client. (characters) +#api_client_max_url_len = 256 diff --git a/src/config.rs b/src/config.rs index 0422286..9acaa30 100644 --- a/src/config.rs +++ b/src/config.rs @@ -34,3 +34,69 @@ impl Default for Config { } } } + +impl Config { + pub fn from_toml(input: &[u8]) -> Self { + let toml = boml::parse(str::from_utf8(input).expect("Config is not valid UTF-8")) + .expect("Config is not valid TOML"); + let mut config = Self::default(); + if let Some(v) = toml.get("listen_host") { + config.listen_host = v + .as_string() + .expect("Config: invalid listen_host") + .to_string(); + } + if let Some(v) = toml.get("listen_port") { + config.listen_port = v + .as_integer() + .expect("Config: invalid listen_port") + .try_into() + .expect("Config: invalid listen_port"); + } + if let Some(v) = toml.get("data_dir") { + config.data_dir = v.as_string().expect("Config: invalid data_dir").to_string(); + } + if let Some(v) = toml.get("api_client_user_agent") { + config.api_client_user_agent = v + .as_string() + .expect("Config: invalid api_client_user_agent") + .to_string(); + } + if let Some(v) = toml.get("api_client_max_page") { + config.api_client_max_page = v + .as_integer() + .expect("Config: invalid api_client_max_page") + .try_into() + .expect("Config: invalid api_client_max_page"); + } + if let Some(v) = toml.get("max_entries") { + config.max_entries = v + .as_integer() + .expect("Config: invalid max_entries") + .try_into() + .expect("Config: invalid max_entries"); + } + if let Some(v) = toml.get("max_file_size") { + config.max_file_size = v + .as_integer() + .expect("Config: invalid max_file_size") + .try_into() + .expect("Config: invalid max_file_size"); + } + if let Some(v) = toml.get("max_file_path_len") { + config.max_file_path_len = v + .as_integer() + .expect("Config: invalid max_file_path_len") + .try_into() + .expect("Config: invalid max_file_path_len"); + } + if let Some(v) = toml.get("api_client_max_url_len") { + config.api_client_max_url_len = v + .as_integer() + .expect("Config: invalid api_client_max_url_len") + .try_into() + .expect("Config: invalid api_client_max_url_len"); + } + config + } +} diff --git a/src/main.rs b/src/main.rs index c78c851..4632ace 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,17 +8,43 @@ mod repo; mod server; mod templates; +use std::str::FromStr; + const SUBDIR_REPOS: &str = "repos"; +fn log_level_from_str(input: &str) -> Result { + log::LevelFilter::from_str(input).map_err(|_e| String::from("Invalid log level")) +} + +/// Git repository anonymization server +#[derive(argp::FromArgs)] +struct Blindforge { + /// Path to the config file + #[argp(positional)] + config: String, + + /// Log verbosity level (off|error|warn|info|debug|trace) (default: info) + #[argp( + option, + short = 'v', + default = "log::LevelFilter::Info", + from_str_fn(log_level_from_str) + )] + verbosity: log::LevelFilter, +} + fn main() { + let cli: Blindforge = argp::parse_args_or_exit(argp::DEFAULT); simplelog::TermLogger::init( - simplelog::LevelFilter::Debug, + cli.verbosity, simplelog::Config::default(), simplelog::TerminalMode::Stderr, simplelog::ColorChoice::Auto, ) .unwrap(); - let config = Arc::new(config::Config::default()); + let config = Arc::new(config::Config::from_toml( + &std::fs::read(cli.config).expect("Cannot read config file"), + )); std::fs::DirBuilder::new() .recursive(true) .create(PathBuf::from(&config.data_dir).join(SUBDIR_REPOS))