diff --git a/services/blob/src/config.rs b/services/blob/src/config.rs new file mode 100644 --- /dev/null +++ b/services/blob/src/config.rs @@ -0,0 +1,55 @@ +use aws_sdk_dynamodb::{Endpoint, Region}; +use clap::{builder::FalseyValueParser, Parser}; +use once_cell::sync::Lazy; +use tonic::transport::Uri; +use tracing::info; + +use crate::constants::{ + AWS_REGION, GRPC_SERVER_DEFAULT_PORT, LOCALSTACK_URL, SANDBOX_ENV_VAR, +}; + +#[derive(Parser)] +#[command(version, about, long_about = None)] +pub struct AppConfig { + /// gRPC server listening port + #[arg(long = "port", default_value_t = GRPC_SERVER_DEFAULT_PORT)] + pub grpc_port: u64, + /// Run the service in sandbox + #[arg(long = "sandbox", default_value_t = false)] + // support the env var for compatibility reasons + #[arg(env = SANDBOX_ENV_VAR)] + #[arg(value_parser = FalseyValueParser::new())] + pub is_sandbox: bool, + /// AWS Localstack service URL, applicable in sandbox mode + #[arg(long, default_value_t = LOCALSTACK_URL.to_string())] + pub localstack_url: String, +} + +/// Stores configuration parsed from command-line arguments +/// and environment variables +pub static CONFIG: Lazy = Lazy::new(|| AppConfig::parse()); + +/// Processes the command-line arguments and environment variables. +/// Should be called at the beginning of the `main()` function. +pub(super) fn parse_cmdline_args() { + // force evaluation of the lazy initialized config + Lazy::force(&CONFIG); +} + +/// Provides region/credentials configuration for AWS SDKs +pub async fn load_aws_config() -> aws_types::SdkConfig { + let mut config_builder = + aws_config::from_env().region(Region::new(AWS_REGION)); + + if CONFIG.is_sandbox { + info!( + "Running in sandbox environment. Localstack URL: {}", + &CONFIG.localstack_url + ); + config_builder = config_builder.endpoint_resolver(Endpoint::immutable( + Uri::from_static(&CONFIG.localstack_url), + )); + } + + config_builder.load().await +} diff --git a/services/blob/src/main.rs b/services/blob/src/main.rs --- a/services/blob/src/main.rs +++ b/services/blob/src/main.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod constants; pub mod database; pub mod s3; @@ -5,12 +6,12 @@ pub mod tools; use anyhow::Result; -use aws_sdk_dynamodb::{Endpoint, Region}; +use config::CONFIG; use database::DatabaseClient; use s3::S3Client; use service::{blob::blob_service_server::BlobServiceServer, MyBlobService}; use std::net::SocketAddr; -use tonic::transport::{Server, Uri}; +use tonic::transport::Server; use tracing::info; use tracing_subscriber::filter::{EnvFilter, LevelFilter}; @@ -25,29 +26,14 @@ Ok(()) } -async fn get_aws_config() -> aws_types::SdkConfig { - let mut config_builder = - aws_config::from_env().region(Region::new(constants::AWS_REGION)); - - if tools::is_sandbox_env() { - info!("Running in sandbox environment"); - config_builder = config_builder.endpoint_resolver(Endpoint::immutable( - Uri::from_static(constants::LOCALSTACK_URL), - )); - } - - return config_builder.load().await; -} - async fn run_grpc_server( db_client: DatabaseClient, s3_client: S3Client, ) -> Result<()> { - let addr: SocketAddr = - format!("[::]:{}", constants::GRPC_SERVER_DEFAULT_PORT).parse()?; + let addr: SocketAddr = format!("[::]:{}", CONFIG.grpc_port).parse()?; let blob_service = MyBlobService::new(db_client, s3_client); - info!("Starting gRPC server listening at {}", addr.to_string()); + info!("Starting gRPC server listening at {}", CONFIG.grpc_port); Server::builder() .add_service(BlobServiceServer::new(blob_service)) .serve(addr) @@ -59,8 +45,9 @@ #[tokio::main] async fn main() -> Result<()> { configure_logging()?; + config::parse_cmdline_args(); - let aws_config = get_aws_config().await; + let aws_config = config::load_aws_config().await; let db = database::DatabaseClient::new(&aws_config); let s3 = s3::S3Client::new(&aws_config);