diff --git a/services/blob/src/config.rs b/services/blob/src/config.rs index fd66c55ab..a5a86e126 100644 --- a/services/blob/src/config.rs +++ b/services/blob/src/config.rs @@ -1,52 +1,65 @@ +use anyhow::{ensure, Result}; use aws_sdk_dynamodb::Region; use clap::{builder::FalseyValueParser, Parser}; use once_cell::sync::Lazy; use tracing::info; use crate::constants::{ - AWS_REGION, GRPC_SERVER_DEFAULT_PORT, LOCALSTACK_URL, SANDBOX_ENV_VAR, + AWS_REGION, DEFAULT_GRPC_PORT, DEFAULT_HTTP_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, + #[arg(long, default_value_t = DEFAULT_GRPC_PORT)] + pub grpc_port: u16, + /// HTTP server listening port + #[arg(long, default_value_t = DEFAULT_HTTP_PORT)] + pub http_port: u16, /// 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() { +pub(super) fn parse_cmdline_args() -> Result<()> { // force evaluation of the lazy initialized config - Lazy::force(&CONFIG); + let cfg = Lazy::force(&CONFIG); + + // Perform some additional validation for CLI args + ensure!( + cfg.grpc_port != cfg.http_port, + "gRPC and HTTP ports cannot be the same: {}", + cfg.grpc_port + ); + Ok(()) } /// 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_url(&CONFIG.localstack_url); } config_builder.load().await } diff --git a/services/blob/src/constants.rs b/services/blob/src/constants.rs index f16aa2f25..53f44f47a 100644 --- a/services/blob/src/constants.rs +++ b/services/blob/src/constants.rs @@ -1,48 +1,49 @@ // Assorted constants -pub const GRPC_SERVER_DEFAULT_PORT: u64 = 50051; +pub const DEFAULT_GRPC_PORT: u16 = 50051; +pub const DEFAULT_HTTP_PORT: u16 = 51001; pub const AWS_REGION: &str = "us-east-2"; pub const LOCALSTACK_URL: &str = "http://localstack:4566"; pub const MPSC_CHANNEL_BUFFER_CAPACITY: usize = 1; /// 4MB limit /// /// WARNING: use keeping in mind that grpc adds its own headers to messages /// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md /// so the message that actually is being sent over the network looks like this /// ``` /// [Compressed-Flag] [Message-Length] [Message] /// [Compressed-Flag] 1 byte - added by grpc /// [Message-Length] 4 bytes - added by grpc /// [Message] N bytes - actual data /// ``` /// so for every message we get 5 additional bytes of data /// as [mentioned here](https://github.com/grpc/grpc/issues/15734#issuecomment-396962671), /// gRPC stream may contain more than one message pub const GRPC_CHUNK_SIZE_LIMIT: u64 = 4 * 1024 * 1024; /// See [`GRPC_CHUNK_SIZE_LIMIT`] description for details pub const GRPC_METADATA_SIZE_PER_MESSAGE: u64 = 5; // DynamoDB constants pub const BLOB_TABLE_NAME: &str = "blob-service-blob"; pub const BLOB_TABLE_BLOB_HASH_FIELD: &str = "blobHash"; pub const BLOB_TABLE_S3_PATH_FIELD: &str = "s3Path"; pub const BLOB_TABLE_CREATED_FIELD: &str = "created"; pub const BLOB_REVERSE_INDEX_TABLE_NAME: &str = "blob-service-reverse-index"; pub const BLOB_REVERSE_INDEX_TABLE_HOLDER_FIELD: &str = "holder"; pub const BLOB_REVERSE_INDEX_TABLE_BLOB_HASH_FIELD: &str = "blobHash"; pub const BLOB_REVERSE_INDEX_TABLE_HASH_INDEX_NAME: &str = "blobHash-index"; // Environment variables pub const SANDBOX_ENV_VAR: &str = "COMM_SERVICES_SANDBOX"; pub const LOG_LEVEL_ENV_VAR: &str = tracing_subscriber::filter::EnvFilter::DEFAULT_ENV; // S3 constants pub const BLOB_S3_BUCKET_NAME: &str = "commapp-blob"; pub const S3_MULTIPART_UPLOAD_MINIMUM_CHUNK_SIZE: u64 = 5 * 1024 * 1024; diff --git a/services/blob/src/main.rs b/services/blob/src/main.rs index d4553c403..b8570c9c0 100644 --- a/services/blob/src/main.rs +++ b/services/blob/src/main.rs @@ -1,32 +1,32 @@ pub mod config; pub mod constants; pub mod database; pub mod grpc; pub mod s3; pub mod tools; use anyhow::Result; use tracing_subscriber::filter::{EnvFilter, LevelFilter}; fn configure_logging() -> Result<()> { let filter = EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) .with_env_var(constants::LOG_LEVEL_ENV_VAR) .from_env_lossy(); let subscriber = tracing_subscriber::fmt().with_env_filter(filter).finish(); tracing::subscriber::set_global_default(subscriber)?; Ok(()) } #[tokio::main] async fn main() -> Result<()> { configure_logging()?; - config::parse_cmdline_args(); + config::parse_cmdline_args()?; let aws_config = config::load_aws_config().await; let db = database::DatabaseClient::new(&aws_config); let s3 = s3::S3Client::new(&aws_config); crate::grpc::run_grpc_server(db, s3).await }