From 4b80ce6c3129c609d2be23700cef9116f9b31967 Mon Sep 17 00:00:00 2001 From: Ezra Singh Date: Mon, 12 Aug 2024 18:12:02 -0400 Subject: [PATCH] Added support environment variables (#14) --- contrib/docs/src/chapter_3_1.md | 16 +++++++++++++-- contrib/docs/src/chapter_3_2.md | 2 +- geoprox/CHANGELOG.md | 2 ++ geoprox/Cargo.toml | 2 +- geoprox/README.md | 14 +++++++++++-- geoprox/src/cli.rs | 30 +++++++++++++++------------ geoprox/src/main.rs | 36 +++++++++------------------------ 7 files changed, 57 insertions(+), 45 deletions(-) diff --git a/contrib/docs/src/chapter_3_1.md b/contrib/docs/src/chapter_3_1.md index ecf3c87..e385c45 100644 --- a/contrib/docs/src/chapter_3_1.md +++ b/contrib/docs/src/chapter_3_1.md @@ -1,8 +1,8 @@ # Configuration -Geoprox allows specifying a configuration file using the `-c` or `--config` option. This file can contain various settings to customize the behavior of the Geoprox server and commands. The configuration can be provided in any common format such as `YAML`, `TOML`, `JSON`, or `INI`. +Geoprox allows specifying a configuration file using the `-c` or `--config` option or set the `GEOPROX_CONFIG` environment variable. This file can contain various settings to customize the behavior of the Geoprox server and commands. The configuration can be provided in any common format such as `YAML`, `TOML`, `JSON`, or `INI`. -### Example Configuration +## Example Config Here's an example configuration file in `TOML` format: @@ -13,6 +13,8 @@ Here's an example configuration file in `TOML` format: http_addr = '0.0.0.0' # The port the server will listen on http_port = 5000 +# Timeout duration in seconds +timeout = 10 [shard] # Determines the default geohash length for inserts @@ -25,6 +27,16 @@ default_count = 100 default_sorted = false ``` +### Environment Variables + +These are the currently supported environment variables. They will take precedence over settings defined in the configuration file. + +| Environment Variable | Description | Default Value | +| -------------------- | -------------------------------------- | --------------------------- | +| `GEOPROX_CONFIG` | Specifies the configuration file path. | `/etc/geoprox/geoprox.toml` | +| `GEOPROX_HTTP_ADDR` | The address the server will bind to. | `0.0.0.0` | +| `GEOPROX_HTTP_PORT` | The port the server will listen on. | `5000` | + ## Fine Tuning The `insert_depth` and `search_depth` settings control the precision of geohashing and impact the performance of distance calculations and search queries. diff --git a/contrib/docs/src/chapter_3_2.md b/contrib/docs/src/chapter_3_2.md index cab2ae4..296c382 100644 --- a/contrib/docs/src/chapter_3_2.md +++ b/contrib/docs/src/chapter_3_2.md @@ -43,7 +43,7 @@ Check the repesctive registry for available tags. ### Customizing the Configuration -> For complete settings and configuration details, refer to the [Geoprox CLI README](../../geoprox/README.md#configuration). +> For complete settings and configuration details, refer to the [Geoprox CLI README](https://github.com/ezrasingh/geoprox/blob/main/geoprox/README.md#configuration). To use a custom configuration file, simply mount your configuration file into the container at `/etc/geoprox`. Geoprox will automatically detect and parse configuration files in formats like `YAML`, `TOML`, `JSON`, or `INI` if they are named `geoprox.yaml`, `geoprox.toml`, `geoprox.json`, or `geoprox.ini`, respectively. diff --git a/geoprox/CHANGELOG.md b/geoprox/CHANGELOG.md index 4708e3f..9ba0dde 100644 --- a/geoprox/CHANGELOG.md +++ b/geoprox/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Added support for environment variables ([#6](https://github.com/ezrasingh/geoprox/issues/6)). + ## 0.4.1 - Added support for `default_count` and `default_sorted` in config ([#2](https://github.com/ezrasingh/geoprox/issues/2)). diff --git a/geoprox/Cargo.toml b/geoprox/Cargo.toml index a3b6961..0834269 100644 --- a/geoprox/Cargo.toml +++ b/geoprox/Cargo.toml @@ -14,7 +14,7 @@ license = "MIT OR Apache-2.0" [dependencies] geoprox-core = { path = "../geoprox-core", version = "0.4.1" } geoprox-server = { path = "../geoprox-server", version = "0.4.1" } -clap = { version = "4.5.4", features = ["derive"] } +clap = { version = "4.5.4", features = ["derive", "env"] } serde = { version = "1.0.199", features = ["derive", "rc"] } serde_json = "1.0.116" config = "0.14.0" diff --git a/geoprox/README.md b/geoprox/README.md index 6422a75..2fac1a8 100644 --- a/geoprox/README.md +++ b/geoprox/README.md @@ -65,9 +65,9 @@ geoprox help encode ## Configuration -Geoprox allows specifying a configuration file using the `-c` or `--config` option. This file can contain various settings to customize the behavior of the Geoprox server and commands. The configuration can be provided in any common format such as `YAML`, `TOML`, `JSON`, or `INI`. +Geoprox allows specifying a configuration file using the `-c` or `--config` option or set the `GEOPROX_CONFIG` environment variable. This file can contain various settings to customize the behavior of the Geoprox server and commands. The configuration can be provided in any common format such as `YAML`, `TOML`, `JSON`, or `INI`. -### Example Configuration +### Example Config Here's an example configuration file in `TOML` format: @@ -92,6 +92,16 @@ default_count = 100 default_sorted = false ``` +#### Environment Variables + +These are the currently supported environment variables. They will take precedence over settings defined in the configuration file. + +| Environment Variable | Description | Default Value | +| -------------------- | -------------------------------------- | --------------------------- | +| `GEOPROX_CONFIG` | Specifies the configuration file path. | `/etc/geoprox/geoprox.toml` | +| `GEOPROX_HTTP_ADDR` | The address the server will bind to. | `0.0.0.0` | +| `GEOPROX_HTTP_PORT` | The port the server will listen on. | `5000` | + ## Fine Tuning Geohashes divide the world into a grid of cells, each with a unique identifier (encoded in base 32). The precision of the geohash can be adjusted by changing its length: diff --git a/geoprox/src/cli.rs b/geoprox/src/cli.rs index ce61329..2bc561c 100644 --- a/geoprox/src/cli.rs +++ b/geoprox/src/cli.rs @@ -3,14 +3,14 @@ use config::{Config, ConfigError}; use geoprox_core::models::GeoShardConfig; use geoprox_server::config::ServerConfig; use serde::Deserialize; -use std::net::SocketAddr; +use std::net::IpAddr; use std::path::PathBuf; #[derive(Parser)] #[command(version, about, long_about = None)] pub struct Cli { /// Specify a config file - #[arg(short, long, value_name = "CONFIG")] + #[arg(short, long, value_name = "CONFIG", env = "GEOPROX_CONFIG")] config: Option, #[command(subcommand)] @@ -21,9 +21,13 @@ pub struct Cli { pub enum Commands { /// Start Geoprox server Run { - /// : (defaults to 0.0.0.0:5000) - #[arg(short, long)] - bind: Option, + /// The address the server will bind to + #[arg(short, long, default_value = "0.0.0.0", env = "GEOPROX_HTTP_ADDR")] + addr: IpAddr, + + /// The port the server will listen on + #[arg(short, long, default_value_t = 5000, env = "GEOPROX_HTTP_PORT")] + port: u16, }, /// Hash latitude/longitude into geohash @@ -36,9 +40,9 @@ pub enum Commands { #[arg(long)] lng: f64, - /// Geohash length (defaults to 6) - #[arg(short, long)] - depth: Option, + /// Geohash length + #[arg(short, long, default_value_t = geoprox_core::shard::GeoShard::DEFAULT_DEPTH)] + depth: usize, }, /// Decode geohash into approximate longitude/latitude @@ -69,26 +73,26 @@ pub enum Commands { } #[derive(Debug, Default, Deserialize)] -pub struct GeoProxConfig { +pub struct GeoproxConfig { pub server: Option, pub shard: Option, } -pub fn runtime() -> Result<(Option, GeoProxConfig), ConfigError> { +pub fn runtime() -> Result<(Option, GeoproxConfig), ConfigError> { let cli = Cli::parse(); - let settings: GeoProxConfig = match cli.config.as_deref() { + + let settings: GeoproxConfig = match cli.config.as_deref() { Some(config_path) => Config::builder() .add_source(config::File::from(config_path)) - .add_source(config::Environment::with_prefix("GEOPROX")) .build()? .try_deserialize()?, None => Config::builder() .add_source(config::File::with_name("/etc/geoprox/geoprox")) - .add_source(config::Environment::with_prefix("GEOPROX")) .build() .unwrap_or_default() .try_deserialize() .unwrap_or_default(), }; + Ok((cli.command, settings)) } diff --git a/geoprox/src/main.rs b/geoprox/src/main.rs index c28cede..d994bbe 100644 --- a/geoprox/src/main.rs +++ b/geoprox/src/main.rs @@ -1,7 +1,5 @@ -use std::io::Write; - -use geoprox_core::models::GeoShardConfig; use geoprox_server::config::ServerConfig; +use std::io::Write; mod cli; @@ -9,31 +7,17 @@ fn main() { let (command, settings) = cli::runtime().unwrap(); match &command { - Some(cli::Commands::Run { bind }) => { - let server_conf: ServerConfig = settings.server.unwrap_or_default(); - let shard_conf: GeoShardConfig = settings.shard.unwrap_or_default(); - - if let Some(socket) = bind { - // ? merge arguments with any existing config - geoprox_server::run( - ServerConfig { - http_addr: Some(socket.ip()), - http_port: Some(socket.port()), - ..server_conf - }, - shard_conf, - ) - } else { - geoprox_server::run(server_conf, shard_conf); - } - } + Some(cli::Commands::Run { addr, port }) => geoprox_server::run( + ServerConfig { + http_addr: Some(*addr), + http_port: Some(*port), + ..settings.server.unwrap_or_default() + }, + settings.shard.unwrap_or_default(), + ), Some(cli::Commands::Encode { lat, lng, depth }) => { - let ghash = geoprox_core::geohash::encode( - [*lng, *lat].into(), - depth.unwrap_or(geoprox_core::shard::GeoShard::DEFAULT_DEPTH), - ) - .unwrap(); + let ghash = geoprox_core::geohash::encode([*lng, *lat].into(), *depth).unwrap(); println!("{}", ghash); }