agentmux_srv\backend/
sigutil.rs

1#![allow(dead_code)]
2// Copyright 2025-2026, AgentMux Corp.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Signal handling utilities.
6//! Port of Go's `pkg/util/sigutil/sigutil.go`.
7//!
8//! Installs OS signal handlers (SIGTERM, SIGINT, SIGHUP) that call a
9//! shutdown callback. Uses tokio for async signal handling.
10
11
12/// Install shutdown signal handlers that call `do_shutdown` with a description.
13///
14/// Spawns a tokio task that waits for SIGTERM, SIGINT, or SIGHUP (on Unix)
15/// and calls the provided callback.
16///
17/// # Panics
18/// Panics if called outside a tokio runtime.
19#[cfg(unix)]
20pub fn install_shutdown_signal_handlers<F>(do_shutdown: F)
21where
22    F: Fn(String) + Send + 'static,
23{
24    tokio::spawn(async move {
25        use tokio::signal::unix::{signal, SignalKind};
26
27        let mut sigterm = signal(SignalKind::terminate()).expect("failed to register SIGTERM");
28        let mut sigint = signal(SignalKind::interrupt()).expect("failed to register SIGINT");
29        let mut sighup = signal(SignalKind::hangup()).expect("failed to register SIGHUP");
30
31        tokio::select! {
32            _ = sigterm.recv() => do_shutdown("got signal SIGTERM".to_string()),
33            _ = sigint.recv() => do_shutdown("got signal SIGINT".to_string()),
34            _ = sighup.recv() => do_shutdown("got signal SIGHUP".to_string()),
35        }
36    });
37}
38
39/// Install shutdown signal handlers (Windows version).
40///
41/// On Windows, only Ctrl+C (SIGINT equivalent) is supported.
42#[cfg(not(unix))]
43pub fn install_shutdown_signal_handlers<F>(do_shutdown: F)
44where
45    F: Fn(String) + Send + 'static,
46{
47    tokio::spawn(async move {
48        tokio::signal::ctrl_c()
49            .await
50            .expect("failed to register ctrl-c handler");
51        do_shutdown("got signal ctrl-c".to_string());
52    });
53}
54
55#[cfg(test)]
56mod tests {
57    // Signal handler tests are inherently integration-level since they require
58    // a running tokio runtime and actual signal delivery. We test the API
59    // compiles and basic setup works.
60
61    #[test]
62    fn test_handler_type_signature() {
63        // Verify the callback signature is correct
64        fn _assert_send<F: Fn(String) + Send + 'static>(_f: F) {}
65        _assert_send(|msg: String| {
66            let _ = msg;
67        });
68    }
69}