From 251fbbb2861eadcf75faa7386cc8a794d08b08e7 Mon Sep 17 00:00:00 2001 From: Markus Brueckner Date: Sun, 11 May 2025 09:04:53 +0200 Subject: [PATCH] improve configuration & documentation --- README.md | 24 +++++++++++++++++++++++- src/access.rs | 13 ++++++++++--- src/config.rs | 8 +++++--- src/main.rs | 30 ++++++++++++++++++------------ 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 0549ee7..85decbc 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,25 @@ # enex-rcache - remote build cache implementation for Nx -This is an implementation of the [Nx remote cache OpenAPI specification](https://nx.dev/recipes/running-tasks/self-hosted-caching#open-api-specification). \ No newline at end of file +This is an implementation of the +[Nx remote cache OpenAPI specification](https://nx.dev/recipes/running-tasks/self-hosted-caching#open-api-specification). + +## Configuration + +enex-rcache takes its configuration from enviroment variables. Currently the +following are supported: + +- `ENEX_CACHE_DIR` (required) - The directory in which to store cache records +- `ENEX_READ_TOKENS` - Comma-separated list of tokens able to read from the + cache, but not write to it. + + _Note:_ If this list is empty, this cache does not have read-only users (i.e. + all users _must_ have read-write tokens). +- `ENEX_READ_WRITE_TOKENS` (required) - Comma-separated list of tokens to write + to the cache. Writing implies being able to read. +- `ENEX_BIND_ADDRESSES` - comma-separated list of IP addresses to bind the + service to. If empty the service will bind to all available interfaces. + +enex-rcache will try to read a `.env` file at startup in order to set the +environment. Existing enviroment entries will take precedence over the contents +of the `.env` file (so you can have a standard config in a file and override it +from the environment, e.g. in containerized deployments). diff --git a/src/access.rs b/src/access.rs index a4c7728..b6a0ff0 100644 --- a/src/access.rs +++ b/src/access.rs @@ -11,10 +11,17 @@ pub enum AccessLevel { pub fn get_access_level(config: &AppConfig, token: &str) -> Option { if config.read_write_tokens.contains(token) { Some(AccessLevel::ReadWrite) - } else if config.read_tokens.contains(token) { - Some(AccessLevel::Read) } else { - None + match &config.read_tokens { + Some(tokens) => { + if tokens.contains(token) { + Some(AccessLevel::Read) + } else { + None + } + } + None => None, + } } } diff --git a/src/config.rs b/src/config.rs index f17700d..278ed93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,11 +4,12 @@ use serde::Deserialize; use config::{Config, Environment}; -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Clone)] pub struct AppConfig { pub cache_dir: String, - pub read_tokens: HashSet, + pub read_tokens: Option>, pub read_write_tokens: HashSet, + pub bind_addresses: Option>, } pub fn load_config() -> AppConfig { @@ -18,7 +19,8 @@ pub fn load_config() -> AppConfig { .try_parsing(true) .list_separator(",") .with_list_parse_key("read_tokens") - .with_list_parse_key("read_write_tokens"), + .with_list_parse_key("read_write_tokens") + .with_list_parse_key("bind_addresses"), ) .build() .expect("Could not initialize config."); diff --git a/src/main.rs b/src/main.rs index 1240466..39bed5c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,16 +17,22 @@ async fn main() -> std::io::Result<()> { dotenv().expect("Could not load .env file."); - HttpServer::new(|| { - let config = config::load_config(); - App::new() - .app_data(Data::new(config)) - .wrap(actix_web::middleware::Logger::default()) - .service(handlers::get_cache_item) - .service(handlers::put_cache_item) - }) - .bind(("127.0.0.1", 8080))? - .bind(("::1", 8080))? - .run() - .await + let config = config::load_config(); + + let mut server = HttpServer::new({ + let config = config.clone(); + move || { + App::new() + .app_data(Data::new(config.clone())) + .wrap(actix_web::middleware::Logger::default()) + .service(handlers::get_cache_item) + .service(handlers::put_cache_item) + } + }); + for bind_address in config.bind_addresses.unwrap_or(vec!["::0".to_string()]) { + server = server + .bind((bind_address.clone(), 8080)) + .expect(format!("Should have been able to bind to address {}", bind_address).as_str()); + } + server.run().await }