d_engine/config/
mod.rs

1//! Configuration management module for distributed Raft consensus engine.
2//!
3//! Provides hierarchical configuration loading and validation with:
4//! - Default values as code base
5//! - Environment variable overrides
6//! - Configuration file support
7//! - Component-wise validation
8mod cluster;
9use std::fmt::Debug;
10mod monitoring;
11mod network;
12mod raft;
13mod retry;
14mod tls;
15pub use cluster::*;
16pub use monitoring::*;
17pub use network::*;
18pub use raft::*;
19pub use retry::*;
20pub use tls::*;
21
22#[cfg(test)]
23mod config_test;
24#[cfg(test)]
25mod raft_test;
26
27//---
28use std::env;
29
30use config::Config;
31use config::Environment;
32use config::File;
33use serde::Deserialize;
34use serde::Serialize;
35
36use crate::Result;
37
38/// Main configuration container for Raft consensus engine components
39///
40/// Combines all subsystem configurations with hierarchical override support:
41/// 1. Default values from code implementation
42/// 2. Configuration file specified by `CONFIG_PATH`
43/// 3. Environment variables (highest priority)
44#[derive(Serialize, Deserialize, Clone, Default)]
45pub struct RaftNodeConfig {
46    /// Cluster topology and node configuration
47    pub cluster: ClusterConfig,
48    /// Metrics and monitoring settings
49    pub monitoring: MonitoringConfig,
50    /// Network communication parameters
51    pub network: NetworkConfig,
52    /// Core Raft algorithm parameters
53    pub raft: RaftConfig,
54    /// Retry policies for distributed operations
55    pub retry: RetryPolicies,
56    /// TLS/SSL security configuration
57    pub tls: TlsConfig,
58}
59impl Debug for RaftNodeConfig {
60    fn fmt(
61        &self,
62        f: &mut std::fmt::Formatter<'_>,
63    ) -> std::fmt::Result {
64        f.debug_struct("RaftNodeConfig")
65            .field("cluster", &self.cluster)
66            .finish()
67    }
68}
69impl RaftNodeConfig {
70    /// Creates a new configuration with hierarchical override support:
71    ///
72    /// Configuration sources are merged in the following order (later sources
73    /// override earlier ones):
74    /// 1. Type defaults (lowest priority)
75    /// 2. Configuration file from `CONFIG_PATH` environment variable
76    /// 3. Environment variables with `RAFT__` prefix (highest priority)
77    ///
78    /// # Returns
79    /// Merged configuration instance or error if:
80    /// - Config file parsing fails
81    /// - Validation rules are violated
82    ///
83    /// # Example
84    /// ```ignore
85    /// // Load with default values only
86    /// let cfg = RaftNodeConfig::new()?;
87    ///
88    /// // Load with config file and environment variables
89    /// std::env::set_var("CONFIG_PATH", "config/cluster.toml");
90    /// std::env::set_var("RAFT__CLUSTER__NODE_ID", "100");
91    /// let cfg = RaftNodeConfig::new()?;
92    /// ```
93    pub fn new() -> Result<Self> {
94        // Create a basic configuration builder
95        // 1. Default values ​​as the base layer
96        let mut builder = Config::builder().add_source(Config::try_from(&Self::default())?);
97
98        // 2. Conditionally add configuration files
99        if let Ok(config_path) = env::var("CONFIG_PATH") {
100            builder = builder.add_source(File::with_name(&config_path));
101        }
102
103        // 3. Add environment variable source
104        builder = builder.add_source(
105            Environment::with_prefix("RAFT")
106                .separator("__")
107                .ignore_empty(true)
108                .try_parsing(true),
109        );
110
111        // Build and deserialize
112        let config: Self = builder.build()?.try_deserialize()?;
113        config.validate()?;
114        Ok(config)
115    }
116
117    /// Creates a new configuration with additional overrides:
118    ///
119    /// Merging order (later sources override earlier ones):
120    /// 1. Current configuration values
121    /// 2. New configuration file
122    /// 3. Latest environment variables (highest priority)
123    ///
124    /// # Example
125    /// ```ignore
126    /// // Initial configuration
127    /// let base = RaftNodeConfig::new()?;
128    ///
129    /// // Apply runtime overrides
130    /// let final_cfg = base.with_override_config("runtime_overrides.toml")?;
131    /// ```
132    pub fn with_override_config(
133        &self,
134        path: &str,
135    ) -> Result<Self> {
136        let config: Self = Config::builder()
137            .add_source(Config::try_from(self)?) // Current config
138            .add_source(File::with_name(path)) // New overrides
139            .add_source(
140                // Fresh environment
141                Environment::with_prefix("RAFT")
142                    .separator("__")
143                    .ignore_empty(true)
144                    .try_parsing(true),
145            )
146            .build()?
147            .try_deserialize()?;
148        config.validate()?;
149        Ok(config)
150    }
151
152    /// Validates cross-component configuration rules
153    ///
154    /// # Returns
155    /// `Ok(())` if all configurations are valid, or
156    /// `Err(Error)` containing validation failure details
157    ///
158    /// # Errors
159    /// Returns validation errors from any subsystem:
160    /// - Invalid port bindings
161    /// - Conflicting node IDs
162    /// - Expired certificates
163    /// - Retry policy conflicts
164    pub fn validate(&self) -> Result<()> {
165        self.cluster.validate()?;
166        self.monitoring.validate()?;
167        self.raft.validate()?;
168        self.network.validate()?;
169        self.tls.validate()?;
170        self.retry.validate()?;
171        Ok(())
172    }
173}