use std::sync::{Arc, Mutex, OnceLock, Weak};
use futures::executor::block_on;
use futures::future::join_all;
use tracing::{info, warn};
use crate::error::{Error, ErrorKind, Result};
use super::server::Server;
static SERVERS: Mutex<Vec<Weak<Server>>> = Mutex::new(Vec::new());
static INSTALLED: OnceLock<std::result::Result<(), String>> = OnceLock::new();
pub fn install() -> Result<()> {
INSTALLED.get_or_init(|| ctrlc::set_handler(stop_all).map_err(|err| err.to_string()))
.clone()
.map_err(|err| Error::new(ErrorKind::Internal)
.with_description(format!("Cannot stop the server on signals, which can be disabled on its builder: {err}")))
}
pub fn register(server: &Arc<Server>) {
let mut servers = SERVERS.lock().unwrap();
servers.retain(|server| server.strong_count() > 0);
servers.push(Arc::downgrade(server));
}
fn stop_all() {
let servers = SERVERS.lock().unwrap().iter()
.filter_map(Weak::upgrade)
.collect::<Vec<_>>();
info!(servers = servers.len(), "Stopping on a termination signal");
let stopped = block_on(join_all(servers.iter().map(|server| server.stop())));
for (server, stopped) in servers.iter().zip(stopped) {
if let Err(err) = stopped {
warn!(server = %server.name(), %err, "Failed to unexport the server stopped on a signal");
}
}
}