improve configuration & documentation

This commit is contained in:
Markus Brueckner 2025-05-11 09:04:53 +02:00
parent 7df6cb5df0
commit 251fbbb286
4 changed files with 56 additions and 19 deletions

View file

@ -1,3 +1,25 @@
# enex-rcache - remote build cache implementation for Nx # 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). 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).

View file

@ -11,10 +11,17 @@ pub enum AccessLevel {
pub fn get_access_level(config: &AppConfig, token: &str) -> Option<AccessLevel> { pub fn get_access_level(config: &AppConfig, token: &str) -> Option<AccessLevel> {
if config.read_write_tokens.contains(token) { if config.read_write_tokens.contains(token) {
Some(AccessLevel::ReadWrite) Some(AccessLevel::ReadWrite)
} else if config.read_tokens.contains(token) {
Some(AccessLevel::Read)
} else { } else {
None match &config.read_tokens {
Some(tokens) => {
if tokens.contains(token) {
Some(AccessLevel::Read)
} else {
None
}
}
None => None,
}
} }
} }

View file

@ -4,11 +4,12 @@ use serde::Deserialize;
use config::{Config, Environment}; use config::{Config, Environment};
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize, Clone)]
pub struct AppConfig { pub struct AppConfig {
pub cache_dir: String, pub cache_dir: String,
pub read_tokens: HashSet<String>, pub read_tokens: Option<HashSet<String>>,
pub read_write_tokens: HashSet<String>, pub read_write_tokens: HashSet<String>,
pub bind_addresses: Option<Vec<String>>,
} }
pub fn load_config() -> AppConfig { pub fn load_config() -> AppConfig {
@ -18,7 +19,8 @@ pub fn load_config() -> AppConfig {
.try_parsing(true) .try_parsing(true)
.list_separator(",") .list_separator(",")
.with_list_parse_key("read_tokens") .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() .build()
.expect("Could not initialize config."); .expect("Could not initialize config.");

View file

@ -17,16 +17,22 @@ async fn main() -> std::io::Result<()> {
dotenv().expect("Could not load .env file."); dotenv().expect("Could not load .env file.");
HttpServer::new(|| { let config = config::load_config();
let config = config::load_config();
App::new() let mut server = HttpServer::new({
.app_data(Data::new(config)) let config = config.clone();
.wrap(actix_web::middleware::Logger::default()) move || {
.service(handlers::get_cache_item) App::new()
.service(handlers::put_cache_item) .app_data(Data::new(config.clone()))
}) .wrap(actix_web::middleware::Logger::default())
.bind(("127.0.0.1", 8080))? .service(handlers::get_cache_item)
.bind(("::1", 8080))? .service(handlers::put_cache_item)
.run() }
.await });
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
} }