use crate::core::error::{Error, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
pub mod credentials;
pub mod loader;
pub mod resilience;
pub mod validation;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PandRSConfig {
pub database: DatabaseConfig,
pub cloud: CloudConfig,
pub performance: PerformanceConfig,
pub security: SecurityConfig,
pub logging: LoggingConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
pub default_url: Option<String>,
pub pool: ConnectionPoolConfig,
pub timeouts: TimeoutConfig,
pub ssl: SslConfig,
pub parameters: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConnectionPoolConfig {
pub max_connections: u32,
pub min_idle: u32,
pub max_lifetime: u64,
pub idle_timeout: u64,
pub acquire_timeout: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeoutConfig {
pub query: u64,
pub connection: u64,
pub transaction: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SslConfig {
pub enabled: bool,
pub mode: String,
pub cert_file: Option<String>,
pub key_file: Option<String>,
pub ca_file: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CloudConfig {
pub aws: AwsConfig,
pub gcp: GcpConfig,
pub azure: AzureConfig,
pub default_provider: Option<String>,
pub global: GlobalCloudConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AwsConfig {
pub region: Option<String>,
pub endpoint_url: Option<String>,
pub access_key_id: Option<String>,
pub secret_access_key: Option<String>,
pub session_token: Option<String>,
pub profile: Option<String>,
pub use_instance_metadata: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GcpConfig {
pub project_id: Option<String>,
pub service_account_key: Option<String>,
pub use_default_credentials: bool,
pub endpoint_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AzureConfig {
pub account_name: Option<String>,
pub account_key: Option<String>,
pub sas_token: Option<String>,
pub use_managed_identity: bool,
pub endpoint_url: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GlobalCloudConfig {
pub timeout: u64,
pub max_retries: u32,
pub retry_backoff: f64,
pub compression: bool,
pub buffer_size: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConfig {
pub threading: ThreadingConfig,
pub memory: MemoryConfig,
pub caching: CachingConfig,
pub jit: JitConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThreadingConfig {
pub worker_threads: usize,
pub parallel_enabled: bool,
pub parallel_batch_size: usize,
pub stack_size: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryConfig {
pub limit: usize,
pub enable_mmap: bool,
pub string_pool: StringPoolConfig,
pub gc: GcConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StringPoolConfig {
pub enabled: bool,
pub max_size: usize,
pub cleanup_threshold: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GcConfig {
pub auto_gc: bool,
pub trigger_mb: usize,
pub aggressive: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CachingConfig {
pub enabled: bool,
pub size_limit: usize,
pub ttl: u64,
pub cleanup_interval: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JitConfig {
pub enabled: bool,
pub threshold: usize,
pub simd_enabled: bool,
pub cache_functions: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
pub encryption: EncryptionConfig,
pub audit: AuditConfig,
pub access_control: AccessControlConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptionConfig {
pub enabled: bool,
pub algorithm: String,
pub key_derivation: String,
pub salt: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditConfig {
pub enabled: bool,
pub level: String,
pub file_path: Option<String>,
pub include_sensitive: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessControlConfig {
pub enabled: bool,
pub allowed_operations: Vec<String>,
pub restricted_patterns: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
pub level: String,
pub format: String,
pub file_path: Option<String>,
pub console: bool,
pub rotation: LogRotationConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogRotationConfig {
pub enabled: bool,
pub max_size: usize,
pub max_files: usize,
pub compress: bool,
}
impl Default for PandRSConfig {
fn default() -> Self {
Self {
database: DatabaseConfig::default(),
cloud: CloudConfig::default(),
performance: PerformanceConfig::default(),
security: SecurityConfig::default(),
logging: LoggingConfig::default(),
}
}
}
impl Default for DatabaseConfig {
fn default() -> Self {
Self {
default_url: None,
pool: ConnectionPoolConfig::default(),
timeouts: TimeoutConfig::default(),
ssl: SslConfig::default(),
parameters: HashMap::new(),
}
}
}
impl Default for ConnectionPoolConfig {
fn default() -> Self {
Self {
max_connections: 10,
min_idle: 1,
max_lifetime: 3600, idle_timeout: 600, acquire_timeout: 30,
}
}
}
impl Default for TimeoutConfig {
fn default() -> Self {
Self {
query: 30,
connection: 10,
transaction: 60,
}
}
}
impl Default for SslConfig {
fn default() -> Self {
Self {
enabled: false,
mode: "prefer".to_string(),
cert_file: None,
key_file: None,
ca_file: None,
}
}
}
impl Default for CloudConfig {
fn default() -> Self {
Self {
aws: AwsConfig::default(),
gcp: GcpConfig::default(),
azure: AzureConfig::default(),
default_provider: None,
global: GlobalCloudConfig::default(),
}
}
}
impl Default for AwsConfig {
fn default() -> Self {
Self {
region: None,
endpoint_url: None,
access_key_id: None,
secret_access_key: None,
session_token: None,
profile: None,
use_instance_metadata: false,
}
}
}
impl Default for GcpConfig {
fn default() -> Self {
Self {
project_id: None,
service_account_key: None,
use_default_credentials: true,
endpoint_url: None,
}
}
}
impl Default for AzureConfig {
fn default() -> Self {
Self {
account_name: None,
account_key: None,
sas_token: None,
use_managed_identity: false,
endpoint_url: None,
}
}
}
impl Default for GlobalCloudConfig {
fn default() -> Self {
Self {
timeout: 300, max_retries: 3,
retry_backoff: 2.0,
compression: true,
buffer_size: 64 * 1024, }
}
}
impl Default for PerformanceConfig {
fn default() -> Self {
Self {
threading: ThreadingConfig::default(),
memory: MemoryConfig::default(),
caching: CachingConfig::default(),
jit: JitConfig::default(),
}
}
}
impl Default for ThreadingConfig {
fn default() -> Self {
Self {
worker_threads: 0, parallel_enabled: true,
parallel_batch_size: 1000,
stack_size: 2 * 1024 * 1024, }
}
}
impl Default for MemoryConfig {
fn default() -> Self {
Self {
limit: 0, enable_mmap: true,
string_pool: StringPoolConfig::default(),
gc: GcConfig::default(),
}
}
}
impl Default for StringPoolConfig {
fn default() -> Self {
Self {
enabled: true,
max_size: 100 * 1024 * 1024, cleanup_threshold: 0.8,
}
}
}
impl Default for GcConfig {
fn default() -> Self {
Self {
auto_gc: true,
trigger_mb: 512,
aggressive: false,
}
}
}
impl Default for CachingConfig {
fn default() -> Self {
Self {
enabled: true,
size_limit: 100 * 1024 * 1024, ttl: 3600, cleanup_interval: 300, }
}
}
impl Default for JitConfig {
fn default() -> Self {
Self {
enabled: true,
threshold: 100,
simd_enabled: true,
cache_functions: true,
}
}
}
impl Default for SecurityConfig {
fn default() -> Self {
Self {
encryption: EncryptionConfig::default(),
audit: AuditConfig::default(),
access_control: AccessControlConfig::default(),
}
}
}
impl Default for EncryptionConfig {
fn default() -> Self {
Self {
enabled: false,
algorithm: "AES-256-GCM".to_string(),
key_derivation: "PBKDF2".to_string(),
salt: None,
}
}
}
impl Default for AuditConfig {
fn default() -> Self {
Self {
enabled: false,
level: "info".to_string(),
file_path: None,
include_sensitive: false,
}
}
}
impl Default for AccessControlConfig {
fn default() -> Self {
Self {
enabled: false,
allowed_operations: vec!["*".to_string()],
restricted_patterns: Vec::new(),
}
}
}
impl Default for LoggingConfig {
fn default() -> Self {
Self {
level: "info".to_string(),
format: "text".to_string(),
file_path: None,
console: true,
rotation: LogRotationConfig::default(),
}
}
}
impl Default for LogRotationConfig {
fn default() -> Self {
Self {
enabled: false,
max_size: 100 * 1024 * 1024, max_files: 10,
compress: true,
}
}
}
impl PandRSConfig {
pub fn from_env() -> Result<Self> {
loader::load_from_env()
}
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
loader::load_from_file(path.as_ref())
}
pub fn from_yaml(yaml: &str) -> Result<Self> {
loader::load_from_yaml(yaml)
}
pub fn from_toml(toml: &str) -> Result<Self> {
loader::load_from_toml(toml)
}
pub fn load_with_precedence<P: AsRef<Path>>(config_file: Option<P>) -> Result<Self> {
loader::load_with_precedence(config_file)
}
pub fn validate(&self) -> Result<()> {
validation::validate_config(self)
}
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
loader::save_to_file(self, path.as_ref())
}
pub fn to_yaml(&self) -> Result<String> {
serde_yaml::to_string(self).map_err(|e| {
Error::ConfigurationError(format!("Failed to serialize config to YAML: {}", e))
})
}
pub fn to_toml(&self) -> Result<String> {
toml::to_string(self).map_err(|e| {
Error::ConfigurationError(format!("Failed to serialize config to TOML: {}", e))
})
}
pub fn merge(&mut self, other: &Self) {
if other.database.default_url.is_some() {
self.database.default_url = other.database.default_url.clone();
}
if other.database.pool.max_connections != self.database.pool.max_connections {
self.database.pool.max_connections = other.database.pool.max_connections;
}
if other.database.pool.min_idle != self.database.pool.min_idle {
self.database.pool.min_idle = other.database.pool.min_idle;
}
if other.database.pool.max_lifetime != self.database.pool.max_lifetime {
self.database.pool.max_lifetime = other.database.pool.max_lifetime;
}
if other.database.pool.idle_timeout != self.database.pool.idle_timeout {
self.database.pool.idle_timeout = other.database.pool.idle_timeout;
}
if other.database.pool.acquire_timeout != self.database.pool.acquire_timeout {
self.database.pool.acquire_timeout = other.database.pool.acquire_timeout;
}
if other.database.timeouts.query != self.database.timeouts.query {
self.database.timeouts.query = other.database.timeouts.query;
}
if other.database.timeouts.connection != self.database.timeouts.connection {
self.database.timeouts.connection = other.database.timeouts.connection;
}
if other.database.timeouts.transaction != self.database.timeouts.transaction {
self.database.timeouts.transaction = other.database.timeouts.transaction;
}
if other.database.ssl.enabled != self.database.ssl.enabled {
self.database.ssl.enabled = other.database.ssl.enabled;
}
if other.database.ssl.mode != self.database.ssl.mode {
self.database.ssl.mode = other.database.ssl.mode.clone();
}
if other.database.ssl.cert_file.is_some() {
self.database.ssl.cert_file = other.database.ssl.cert_file.clone();
}
if other.database.ssl.key_file.is_some() {
self.database.ssl.key_file = other.database.ssl.key_file.clone();
}
if other.database.ssl.ca_file.is_some() {
self.database.ssl.ca_file = other.database.ssl.ca_file.clone();
}
for (key, value) in &other.database.parameters {
self.database.parameters.insert(key.clone(), value.clone());
}
if other.cloud.aws.region.is_some() {
self.cloud.aws.region = other.cloud.aws.region.clone();
}
if other.cloud.aws.endpoint_url.is_some() {
self.cloud.aws.endpoint_url = other.cloud.aws.endpoint_url.clone();
}
if other.cloud.aws.access_key_id.is_some() {
self.cloud.aws.access_key_id = other.cloud.aws.access_key_id.clone();
}
if other.cloud.aws.secret_access_key.is_some() {
self.cloud.aws.secret_access_key = other.cloud.aws.secret_access_key.clone();
}
if other.cloud.aws.session_token.is_some() {
self.cloud.aws.session_token = other.cloud.aws.session_token.clone();
}
if other.cloud.aws.profile.is_some() {
self.cloud.aws.profile = other.cloud.aws.profile.clone();
}
if other.cloud.aws.use_instance_metadata != self.cloud.aws.use_instance_metadata {
self.cloud.aws.use_instance_metadata = other.cloud.aws.use_instance_metadata;
}
if other.cloud.gcp.project_id.is_some() {
self.cloud.gcp.project_id = other.cloud.gcp.project_id.clone();
}
if other.cloud.gcp.service_account_key.is_some() {
self.cloud.gcp.service_account_key = other.cloud.gcp.service_account_key.clone();
}
if other.cloud.gcp.use_default_credentials != self.cloud.gcp.use_default_credentials {
self.cloud.gcp.use_default_credentials = other.cloud.gcp.use_default_credentials;
}
if other.cloud.gcp.endpoint_url.is_some() {
self.cloud.gcp.endpoint_url = other.cloud.gcp.endpoint_url.clone();
}
if other.cloud.azure.account_name.is_some() {
self.cloud.azure.account_name = other.cloud.azure.account_name.clone();
}
if other.cloud.azure.account_key.is_some() {
self.cloud.azure.account_key = other.cloud.azure.account_key.clone();
}
if other.cloud.azure.sas_token.is_some() {
self.cloud.azure.sas_token = other.cloud.azure.sas_token.clone();
}
if other.cloud.azure.use_managed_identity != self.cloud.azure.use_managed_identity {
self.cloud.azure.use_managed_identity = other.cloud.azure.use_managed_identity;
}
if other.cloud.default_provider.is_some() {
self.cloud.default_provider = other.cloud.default_provider.clone();
}
}
pub fn get_database_config(&self, _name: &str) -> &DatabaseConfig {
&self.database
}
pub fn get_cloud_config(&self, provider: &str) -> Result<&dyn std::any::Any> {
match provider.to_lowercase().as_str() {
"aws" | "s3" => Ok(&self.cloud.aws),
"gcp" | "gcs" => Ok(&self.cloud.gcp),
"azure" => Ok(&self.cloud.azure),
_ => Err(Error::ConfigurationError(format!(
"Unknown cloud provider: {}",
provider
))),
}
}
}