#![cfg_attr(docsrs, feature(doc_cfg))]
use std::{env, process::Command};
use log::{error, info};
use tokio::task;
pub use tokio_util::sync::CancellationToken;
#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;
#[cfg(unix)]
use unix::wait_reload;
#[cfg(windows)]
use windows::wait_reload;
async fn spawn(token: CancellationToken) {
let current_exe = match env::current_exe() {
Ok(path) => path,
Err(e) => {
error!("NO EXE PATH {e}");
return;
}
};
let args: Vec<String> = env::args().collect();
info!("reload_self : {} {:?}", current_exe.display(), &args[1..]);
let mut command = Command::new(current_exe);
command.args(&args[1..]);
match command.spawn() {
Ok(child) => {
let pid = child.id();
info!("reload_self new process PID={pid}");
#[cfg(target_os = "linux")]
{
if std::env::var("NOTIFY_SOCKET").is_ok() {
use sd_notify::NotifyState;
if let Err(e) = sd_notify::notify(false, &[NotifyState::MainPid(pid)]) {
log::error!("failed to notify systemd: {}", e);
} else {
log::info!("notified systemd MainPid={pid}");
}
}
}
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
token.cancel();
}
Err(e) => {
error!("reload_self : {e}");
}
}
}
pub fn listen() -> Result<CancellationToken, std::io::Error> {
let token = CancellationToken::new();
let token_for_signal = token.clone();
task::spawn(async move {
wait_reload().await;
spawn(token_for_signal).await;
});
Ok(token)
}