"Manager" is a vague suffix, and the workspace had a name clash: opnsense-config defines its own unrelated `ConfigManager` trait. The type's real role is the consumer-facing facade you call to get / set / get_or_prompt over an ordered source chain — a client for accessing config. Renamed to `ConfigClient` (chosen over `ConfigStore`, which collides with the existing SecretStore / StoreSource nomenclature, and `ConfigResolver`, which undersells the write/prompt side). Pure mechanical rename, no behaviour change: - `ConfigManager` → `ConfigClient` - `ConfigManagerBuilder` → `ConfigClientBuilder` - private static `CONFIG_MANAGER` → `CONFIG_CLIENT` - doc prose + intra-doc links across harmony_config, its three examples, and examples/harmony_sso (incl. README + plan.md) The opnsense-config `ConfigManager` trait is a different crate and is untouched — the rename removes the cross-crate clash. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
91 lines
2.7 KiB
Rust
91 lines
2.7 KiB
Rust
//! Basic example showing harmony_config with SQLite backend
|
|
//!
|
|
//! This example demonstrates:
|
|
//! - Zero-setup SQLite backend (no configuration needed)
|
|
//! - Using the `#[derive(Config)]` macro
|
|
//! - Environment variable override (HARMONY_CONFIG_TestConfig overrides SQLite)
|
|
//! - Direct set/get operations (prompting requires a TTY)
|
|
//!
|
|
//! Run with:
|
|
//! - `cargo run --example basic` - creates/reads config from SQLite
|
|
//! - `HARMONY_CONFIG_TestConfig='{"name":"from_env","count":42}' cargo run --example basic` - uses env var
|
|
|
|
use std::sync::Arc;
|
|
|
|
use harmony_config::{Config, ConfigClient, EnvSource, SqliteSource};
|
|
use log::info;
|
|
use schemars::JsonSchema;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Config)]
|
|
struct TestConfig {
|
|
name: String,
|
|
count: u32,
|
|
}
|
|
|
|
impl Default for TestConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
name: "default_name".to_string(),
|
|
count: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() -> anyhow::Result<()> {
|
|
env_logger::init();
|
|
|
|
// Namespace the SQLite file so this example's state doesn't
|
|
// collide with other harmony binaries that also use SqliteSource.
|
|
let sqlite = SqliteSource::for_namespace("harmony_config-basic-example").await?;
|
|
let manager = ConfigClient::new(vec![Arc::new(EnvSource), Arc::new(sqlite)]);
|
|
|
|
info!("1. Attempting to get TestConfig (expect NotFound on first run)...");
|
|
match manager.get::<TestConfig>().await {
|
|
Ok(config) => {
|
|
info!(" Found config: {:?}", config);
|
|
}
|
|
Err(harmony_config::ConfigError::NotFound { .. }) => {
|
|
info!(" NotFound - as expected on first run");
|
|
}
|
|
Err(e) => {
|
|
info!(" Error: {:?}", e);
|
|
}
|
|
}
|
|
|
|
info!("\n2. Setting config directly...");
|
|
let config = TestConfig {
|
|
name: "from_code".to_string(),
|
|
count: 42,
|
|
};
|
|
manager.set(&config).await?;
|
|
info!(" Set config: {:?}", config);
|
|
|
|
info!("\n3. Getting config back from SQLite...");
|
|
let retrieved: TestConfig = manager.get().await?;
|
|
info!(" Retrieved: {:?}", retrieved);
|
|
|
|
info!("\n4. Using env override...");
|
|
info!(" Env var HARMONY_CONFIG_TestConfig overrides SQLite");
|
|
let env_config = TestConfig {
|
|
name: "from_env".to_string(),
|
|
count: 99,
|
|
};
|
|
unsafe {
|
|
std::env::set_var(
|
|
"HARMONY_CONFIG_TestConfig",
|
|
serde_json::to_string(&env_config)?,
|
|
);
|
|
}
|
|
let from_env: TestConfig = manager.get().await?;
|
|
info!(" Got from env: {:?}", from_env);
|
|
unsafe {
|
|
std::env::remove_var("HARMONY_CONFIG_TestConfig");
|
|
}
|
|
|
|
info!("\nDone! Config persisted at ~/.local/share/harmony/config/config.db");
|
|
|
|
Ok(())
|
|
}
|