use arc_swap::ArcSwap;
use ferryman_edge_core::{build_table_ext, parse_config, JwtVerifier, RouteTable, SharedTable};
use std::path::{Path, PathBuf};
use std::sync::Arc;
pub fn spawn_reload(path: PathBuf, table: SharedTable) {
tokio::spawn(async move {
let mut sig =
match tokio::signal::unix::signal(tokio::signal::unix::SignalKind::user_defined1()) {
Ok(s) => s,
Err(e) => {
tracing::error!(?e, "failed to register SIGUSR1 for route reload");
return;
}
};
while sig.recv().await.is_some() {
match reload_once(&path) {
Ok(mut new_table) => {
new_table.inherit_breakers(&table.load());
table.store(Arc::new(new_table));
tracing::info!(path = %path.display(), "routing table reloaded");
}
Err(e) => {
tracing::error!(path = %path.display(), ?e, "route reload failed; keeping old table");
}
}
}
});
}
pub fn spawn_jwt_reload(pem_path: PathBuf, jwt: Arc<JwtVerifier>) {
tokio::spawn(async move {
let mut sig =
match tokio::signal::unix::signal(tokio::signal::unix::SignalKind::user_defined1()) {
Ok(s) => s,
Err(e) => {
tracing::error!(?e, "failed to register SIGUSR1 for JWT key reload");
return;
}
};
while sig.recv().await.is_some() {
match std::fs::read(&pem_path)
.map_err(anyhow::Error::from)
.and_then(|pem| jwt.reload_key(&pem))
{
Ok(()) => tracing::info!(path = %pem_path.display(), "JWT key reloaded"),
Err(e) => {
tracing::error!(path = %pem_path.display(), ?e, "JWT key reload failed; keeping old key")
}
}
}
});
}
fn reload_once(path: &Path) -> anyhow::Result<RouteTable> {
let raw = std::fs::read_to_string(path)?;
let (cfg, ext) = parse_config(&raw)?;
build_table_ext(&cfg, &ext)
}
#[allow(dead_code)]
pub fn new_shared(table: RouteTable) -> SharedTable {
Arc::new(ArcSwap::from_pointee(table))
}