use anyhow::{Context, Result};
use crate::secrets;
const ENV_TOKEN: &str = "KANADE_NATS_TOKEN";
const REG_SUBKEY: &str = r"SOFTWARE\kanade\agent";
const REG_VALUE: &str = "NatsToken";
fn resolve_token() -> Option<String> {
if let Some(t) = secrets::read_hklm_value(REG_SUBKEY, REG_VALUE) {
return Some(t);
}
match std::env::var(ENV_TOKEN) {
Ok(t) if !t.is_empty() => Some(t),
_ => None,
}
}
pub async fn connect(url: &str) -> Result<async_nats::Client> {
connect_inner(url, None::<fn(async_nats::Event) -> std::future::Ready<()>>).await
}
pub async fn connect_with_event_callback<F, Fut>(url: &str, cb: F) -> Result<async_nats::Client>
where
F: Fn(async_nats::Event) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = ()> + Send + Sync + 'static,
{
connect_inner(url, Some(cb)).await
}
async fn connect_inner<F, Fut>(url: &str, cb: Option<F>) -> Result<async_nats::Client>
where
F: Fn(async_nats::Event) -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = ()> + Send + Sync + 'static,
{
let opts = async_nats::ConnectOptions::new();
let opts = match resolve_token() {
Some(token) => opts.token(token),
None => opts,
};
let opts = match cb {
Some(cb) => opts.event_callback(cb),
None => opts,
};
opts.connect(url)
.await
.with_context(|| format!("connect to NATS at {url}"))
}