use std::path::{Path, PathBuf};
use std::time::Duration;
use dynamic_config::dynamic_config;
use serde::Deserialize;
const DIRECTORY: &str = "/tmp/dynamic-config-tokio";
#[dynamic_config(
files = ["/tmp/dynamic-config-tokio/config.json"],
key = "server",
env = "APP_",
watch,
async,
diff,
)]
#[derive(Debug, Deserialize)]
struct ServerConfig {
greeting: String,
workers: usize,
}
fn write(directory: &Path, greeting: &str, workers: usize) -> std::io::Result<()> {
std::fs::write(
directory.join("config.json"),
format!(r#"{{"server": {{"greeting": "{greeting}", "workers": {workers}}}}}"#),
)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let directory = PathBuf::from(DIRECTORY);
std::fs::create_dir_all(&directory)?;
write(&directory, "hello from tokio", 4)?;
ServerConfig::init_async().await?;
println!("loaded: {}", ServerConfig::current().greeting);
println!("workers: {}\n", ServerConfig::current().workers);
let handle = ServerConfig::start_watch()?;
let mut first = ServerConfig::changes();
let mut second = ServerConfig::changes();
let readers = tokio::spawn(async move {
for _ in 0..2 {
let config = first.changed().await;
println!(
" reader A: {} ({} workers)",
config.greeting, config.workers
);
}
});
let other = tokio::spawn(async move {
for _ in 0..2 {
let config = second.changed().await;
println!(
" reader B: {} ({} workers)",
config.greeting, config.workers
);
}
});
let editor = tokio::spawn({
let directory = directory.clone();
async move {
for (greeting, workers) in [("edited once", 8), ("edited twice", 16)] {
tokio::time::sleep(Duration::from_millis(400)).await;
let _ = write(&directory, greeting, workers);
}
}
});
let _ = tokio::join!(readers, other, editor);
drop(handle);
println!("\nfinal: {}", ServerConfig::current().greeting);
println!("\nThe same `changes()` future drives on smol and on Embassy —");
println!("see the other two runtime examples. Only the blocking pool is");
println!("runtime-specific, and it is pluggable.");
let _ = std::fs::remove_dir_all(&directory);
Ok(())
}