use distributed_config::{
sources::EnvSource, sources::FileSource, validation::SchemaValidator, ConfigManager,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
use tokio::time::sleep;
use tracing::info;
#[derive(Debug, Serialize, Deserialize)]
struct DatabaseConfig {
host: String,
port: u16,
username: String,
password: String,
max_connections: u32,
timeout: Duration,
}
#[derive(Debug, Serialize, Deserialize)]
struct ServerConfig {
host: String,
port: u16,
workers: u32,
debug: bool,
}
#[derive(Debug, Serialize, Deserialize)]
struct AppConfig {
name: String,
version: String,
server: ServerConfig,
database: DatabaseConfig,
feature_flags: HashMap<String, bool>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
distributed_config::init_tracing();
println!("๐ Distributed Config - Basic Usage Example");
println!("============================================");
let config_content = r#"
name: "My Application"
version: "1.0.0"
server:
host: "0.0.0.0"
port: 8080
workers: 4
debug: false
database:
host: "localhost"
port: 5432
username: "myuser"
password: "mypassword"
max_connections: 10
timeout: 30
feature_flags:
new_ui: true
beta_feature: false
experimental_caching: true
"#;
tokio::fs::write("example_config.yaml", config_content).await?;
unsafe {
std::env::set_var("APP_SERVER__DEBUG", "true");
std::env::set_var("APP_DATABASE__HOST", "production-db.example.com");
std::env::set_var("APP_FEATURE_FLAGS__NEW_UI", "false");
}
let mut config_manager = ConfigManager::new();
let file_source = FileSource::new().add_file("example_config.yaml", None);
config_manager.add_source(file_source, 10);
let env_source = EnvSource::new().prefix("APP_").separator("__");
config_manager.add_source(env_source, 20);
let validator = SchemaValidator::new()
.add_schema_from_json(
"server",
distributed_config::validation::schemas::server_config(),
)?
.add_schema_from_json(
"database",
distributed_config::validation::schemas::database_config(),
)?
.add_schema_from_json(
"feature_flags",
distributed_config::validation::schemas::feature_flags(),
)?;
config_manager.set_validator(validator);
println!("\n๐ Loading configuration from sources...");
config_manager.initialize().await?;
println!("\n๐ Accessing typed configuration:");
let app_config: AppConfig = config_manager.get("").await?;
println!(" App Name: {}", app_config.name);
println!(" App Version: {}", app_config.version);
println!(
" Server: {}:{}",
app_config.server.host, app_config.server.port
);
println!(
" Server Debug: {} (overridden by env)",
app_config.server.debug
);
println!(
" Database: {}:{}",
app_config.database.host, app_config.database.port
);
println!(
" Database Host: {} (overridden by env)",
app_config.database.host
);
println!("\n๐ฏ Accessing individual values:");
let server_port = config_manager.get_value("server.port").await?;
println!(" Server port: {}", server_port.as_integer()?);
let db_timeout = config_manager.get_value("database.timeout").await?;
println!(
" Database timeout: {} seconds",
db_timeout.as_duration()?.as_secs()
);
println!("\n๐ฉ Feature flags:");
println!(
" New UI: {}",
config_manager.is_feature_enabled("new_ui").await?
);
println!(
" Beta Feature: {}",
config_manager.is_feature_enabled("beta_feature").await?
);
println!(
" Experimental Caching: {}",
config_manager
.is_feature_enabled("experimental_caching")
.await?
);
println!("\nโ๏ธ Updating configuration at runtime:");
config_manager.set_value("server.workers", 8.into()).await?;
let updated_workers = config_manager.get_value("server.workers").await?;
println!(" Workers updated to: {}", updated_workers.as_integer()?);
config_manager
.set_value("feature_flags.new_feature", true.into())
.await?;
println!(
" New feature flag enabled: {}",
config_manager.is_feature_enabled("new_feature").await?
);
println!("\n๐ Configuration history:");
let history = config_manager.get_history("server.workers", 5).await?;
for (i, entry) in history.iter().enumerate() {
println!(
" {}. server.workers = {} (changed by: {})",
i + 1,
entry.value.as_integer().unwrap_or(0),
entry.changed_by
);
}
println!("\n๐พ Saving current configuration:");
config_manager.save_to_file("current_config.yaml").await?;
println!(" Configuration saved to: current_config.yaml");
println!("\n๐ Watching for configuration changes (5 seconds):");
let mut watcher = config_manager.watch("server").await?;
let config_manager_clone = config_manager;
tokio::task::spawn_local(async move {
sleep(Duration::from_secs(2)).await;
info!("Making a configuration change...");
let _ = config_manager_clone
.set_value(
"server.port",
distributed_config::ConfigValue::Integer(9090),
)
.await;
});
tokio::select! {
Some(change) = watcher.next() => {
println!(" ๐ Configuration changed!");
println!(" Key: {}", change.key);
println!(" New value: {:?}", change.new_value);
println!(" Changed by: {}", change.changed_by);
}
_ = sleep(Duration::from_secs(5)) => {
println!(" โฐ Watch timeout (no changes detected)");
}
}
println!("\n๐งน Cleaning up temporary files...");
let _ = tokio::fs::remove_file("example_config.yaml").await;
let _ = tokio::fs::remove_file("current_config.yaml").await;
unsafe {
std::env::remove_var("APP_SERVER__DEBUG");
std::env::remove_var("APP_DATABASE__HOST");
std::env::remove_var("APP_FEATURE_FLAGS__NEW_UI");
}
println!("\nโ
Example completed successfully!");
println!("\nThis example demonstrated:");
println!(" โข Loading configuration from multiple sources (file + environment)");
println!(" โข Source priority (environment variables override file values)");
println!(" โข Type-safe configuration access");
println!(" โข Schema validation");
println!(" โข Feature flag management");
println!(" โข Runtime configuration updates");
println!(" โข Configuration change watching");
println!(" โข Configuration history tracking");
println!(" โข Saving configuration to file");
Ok(())
}