//! Server configuration use lightningstor_distributed::DistributedConfig; use serde::{Deserialize, Serialize}; use std::net::SocketAddr; /// TLS configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TlsConfig { /// Path to certificate file (PEM) pub cert_file: String, /// Path to private key file (PEM) pub key_file: String, /// Path to CA certificate for client verification (optional, for mTLS) pub ca_file: Option, /// Require client certificates (mTLS) #[serde(default)] pub require_client_cert: bool, } /// Metadata storage backend #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum MetadataBackend { /// FlareDB distributed metadata database FlareDb, /// PostgreSQL metadata database Postgres, /// SQLite metadata database (single-node only) Sqlite, } impl Default for MetadataBackend { fn default() -> Self { Self::FlareDb } } /// Object data storage backend #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)] #[serde(rename_all = "snake_case")] pub enum ObjectStorageBackend { /// Store object data directly on the local filesystem. #[default] LocalFs, /// Coordinate object data across LightningStor storage nodes. Distributed, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct S3AuthConfig { #[serde(default = "default_s3_auth_enabled")] pub enabled: bool, #[serde(default = "default_s3_aws_region")] pub aws_region: String, #[serde(default = "default_s3_iam_cache_ttl_secs")] pub iam_cache_ttl_secs: u64, #[serde(default = "default_s3_default_org_id")] pub default_org_id: Option, #[serde(default = "default_s3_default_project_id")] pub default_project_id: Option, #[serde(default = "default_s3_max_auth_body_bytes")] pub max_auth_body_bytes: usize, } impl Default for S3AuthConfig { fn default() -> Self { Self { enabled: default_s3_auth_enabled(), aws_region: default_s3_aws_region(), iam_cache_ttl_secs: default_s3_iam_cache_ttl_secs(), default_org_id: default_s3_default_org_id(), default_project_id: default_s3_default_project_id(), max_auth_body_bytes: default_s3_max_auth_body_bytes(), } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct S3PerformanceConfig { #[serde(default = "default_s3_streaming_put_threshold_bytes")] pub streaming_put_threshold_bytes: usize, #[serde(default = "default_s3_inline_put_max_bytes")] pub inline_put_max_bytes: usize, #[serde(default = "default_s3_multipart_put_concurrency")] pub multipart_put_concurrency: usize, #[serde(default = "default_s3_multipart_fetch_concurrency")] pub multipart_fetch_concurrency: usize, } impl Default for S3PerformanceConfig { fn default() -> Self { Self { streaming_put_threshold_bytes: default_s3_streaming_put_threshold_bytes(), inline_put_max_bytes: default_s3_inline_put_max_bytes(), multipart_put_concurrency: default_s3_multipart_put_concurrency(), multipart_fetch_concurrency: default_s3_multipart_fetch_concurrency(), } } } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct S3Config { #[serde(default)] pub auth: S3AuthConfig, #[serde(default)] pub performance: S3PerformanceConfig, } /// Server configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ServerConfig { /// gRPC address to listen on pub grpc_addr: SocketAddr, /// S3 HTTP API address to listen on pub s3_addr: SocketAddr, /// Log level pub log_level: String, /// ChainFire endpoint for cluster coordination only pub chainfire_endpoint: Option, /// FlareDB endpoint for metadata and tenant data storage pub flaredb_endpoint: Option, /// Metadata backend selection (flaredb, postgres, sqlite) #[serde(default)] pub metadata_backend: MetadataBackend, /// SQL database URL for metadata when backend is postgres or sqlite pub metadata_database_url: Option, /// Allow single-node mode (required for SQLite) #[serde(default)] pub single_node: bool, /// Data directory for object storage pub data_dir: String, /// Object data storage backend selection #[serde(default)] pub object_storage_backend: ObjectStorageBackend, /// Distributed object storage settings (used when backend=distributed) #[serde(default)] pub distributed: DistributedConfig, /// Whether local filesystem writes should be flushed before success is returned. #[serde(default)] pub sync_on_write: bool, /// TLS configuration (optional) pub tls: Option, /// Authentication configuration #[serde(default)] pub auth: AuthConfig, /// S3 API runtime settings #[serde(default)] pub s3: S3Config, } /// Authentication configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AuthConfig { /// IAM server endpoint #[serde(default = "default_iam_server_addr")] pub iam_server_addr: String, } fn default_iam_server_addr() -> String { "127.0.0.1:50051".to_string() } fn default_s3_auth_enabled() -> bool { true } fn default_s3_aws_region() -> String { "us-east-1".to_string() } fn default_s3_iam_cache_ttl_secs() -> u64 { 30 } fn default_s3_default_org_id() -> Option { Some("default".to_string()) } fn default_s3_default_project_id() -> Option { Some("default".to_string()) } fn default_s3_max_auth_body_bytes() -> usize { 1024 * 1024 * 1024 } fn default_s3_streaming_put_threshold_bytes() -> usize { 16 * 1024 * 1024 } fn default_s3_inline_put_max_bytes() -> usize { 128 * 1024 * 1024 } fn default_s3_multipart_put_concurrency() -> usize { 4 } fn default_s3_multipart_fetch_concurrency() -> usize { 4 } impl Default for AuthConfig { fn default() -> Self { Self { iam_server_addr: default_iam_server_addr(), } } } impl Default for ServerConfig { fn default() -> Self { Self { grpc_addr: "0.0.0.0:9000".parse().unwrap(), s3_addr: "0.0.0.0:9001".parse().unwrap(), log_level: "info".to_string(), chainfire_endpoint: None, flaredb_endpoint: None, metadata_backend: MetadataBackend::FlareDb, metadata_database_url: None, single_node: false, data_dir: "/var/lib/lightningstor/data".to_string(), object_storage_backend: ObjectStorageBackend::LocalFs, distributed: DistributedConfig::default(), sync_on_write: false, tls: None, auth: AuthConfig::default(), s3: S3Config::default(), } } }