use std::time::Duration;
use dynamic_config::{dynamic_config, AsyncRemoteSource};
use dynamic_config_etcd::{ConnectOptions, Etcd};
use serde::Deserialize;
#[dynamic_config]
#[derive(Debug, Deserialize)]
struct DbConfig {
host: String,
port: u16,
}
async fn source(endpoint: &str) -> Result<Etcd, dynamic_config::Error> {
Etcd::with_options(
[endpoint],
"myapp/db.json",
ConnectOptions::new().with_keep_alive(Duration::from_secs(30), Duration::from_secs(5)),
)
.await
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoint =
std::env::var("ETCD_ENDPOINT").unwrap_or_else(|_| "http://127.0.0.1:2379".to_owned());
let reader = source(&endpoint).await?;
println!("built a source for {}\n", reader.describe());
DbConfig::set_remote_async(reader);
DbConfig::refresh_remote_async().await?;
DbConfig::builder("db").env("APP_").init_async().await?;
let sink = DbConfig::remote_sink();
println!("host = {}", DbConfig::current().host);
println!("port = {}", DbConfig::current().port);
println!("traced back to: {:?}", DbConfig::source_of("host")?);
println!("\nwatching for 10 seconds — try another `etcdctl put ...`");
let watcher = source(&endpoint).await?;
let task = tokio::spawn(async move {
watcher.watch(move |document| sink.apply(document)).await
});
let mut changes = DbConfig::changes();
let reader = tokio::spawn(async move {
loop {
let config = changes.changed().await;
println!(" a reader woke up: host is now {}", config.host);
}
});
tokio::time::sleep(Duration::from_secs(10)).await;
task.abort();
reader.abort();
println!("\nfinal host = {}", DbConfig::current().host);
Ok(())
}