From b1f1c204847f7801bcb514b7975d936c5b54e339 Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Mon, 3 Oct 2022 00:07:40 +0200 Subject: [PATCH] Exit gracefully on `SIGTERM` * Exit gracefully on `SIGTERM` Save current state and close ncspot on `SIGTERM` Fixes #948 * Disable signal handling on non-UNIX platforms --- Cargo.lock | 1 + Cargo.toml | 4 ++++ src/main.rs | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 45440be..73a8736 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1589,6 +1589,7 @@ dependencies = [ "serde", "serde_cbor", "serde_json", + "signal-hook", "strum 0.24.1", "strum_macros 0.24.3", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 28b9f29..05bb022 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,9 +46,13 @@ toml = "0.5" unicode-width = "0.1.9" url = "2.2" cursive_buffered_backend = "0.6.1" + [target.'cfg(target_os = "linux")'.dependencies] wl-clipboard-rs = {version = "0.7", optional = true} +[target.'cfg(unix)'.dependencies] +signal-hook = "0.3.0" + [dependencies.rspotify] default-features = false features = ["client-ureq", "ureq-rustls-tls"] diff --git a/src/main.rs b/src/main.rs index 0b4a0c4..d507348 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,9 @@ use librespot_core::cache::Cache; use librespot_playback::audio_backend; use log::{error, info, trace}; +#[cfg(unix)] +use signal_hook::{consts::SIGTERM, iterator::Signals}; + mod authentication; mod command; mod commands; @@ -313,9 +316,22 @@ async fn main() -> Result<(), String> { cursive.add_fullscreen_layer(layout.with_name("main")); + // catch SIGTERM to save current state + #[cfg(unix)] + let mut signals = Signals::new(&[SIGTERM]).expect("could not register SIGTERM handler"); + // cursive event loop while cursive.is_running() { cursive.step(); + #[cfg(unix)] + for signal in signals.pending() { + if signal == SIGTERM { + info!("Caught SIGTERM, cleaning up and closing"); + if let Some(data) = cursive.user_data::().cloned() { + data.cmd.handle(&mut cursive, Command::Quit); + } + } + } for event in event_manager.msg_iter() { match event { Event::Player(state) => {