feat: move to async POSIX signal handler
Instead of trying to handle signals for every step of the `cursive` event loop, move the signal handling into its own asynchronous task and send callbacks to `cursive` when a signal arrives.
This commit is contained in:
committed by
Henrik Friedrichsen
parent
209d8e260b
commit
a067ab2ae2
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -1985,6 +1985,7 @@ dependencies = [
|
|||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
|
"signal-hook-tokio",
|
||||||
"strum",
|
"strum",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -3267,6 +3268,18 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-tokio"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"libc",
|
||||||
|
"signal-hook",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ wl-clipboard-rs = {version = "0.7", optional = true}
|
|||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
signal-hook = "0.3.0"
|
signal-hook = "0.3.0"
|
||||||
|
signal-hook-tokio = { version = "0.3.1", features = ["futures-v0_3"] }
|
||||||
|
|
||||||
[dependencies.rspotify]
|
[dependencies.rspotify]
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|||||||
@@ -3,11 +3,15 @@ use std::rc::Rc;
|
|||||||
use std::sync::{Arc, OnceLock};
|
use std::sync::{Arc, OnceLock};
|
||||||
|
|
||||||
use cursive::traits::Nameable;
|
use cursive::traits::Nameable;
|
||||||
use cursive::{Cursive, CursiveRunner};
|
use cursive::{CbSink, Cursive, CursiveRunner};
|
||||||
use log::{error, info, trace};
|
use log::{error, info, trace};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use signal_hook::{consts::SIGHUP, consts::SIGTERM, iterator::Signals};
|
use futures::stream::StreamExt;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use signal_hook::{consts::SIGHUP, consts::SIGTERM};
|
||||||
|
#[cfg(unix)]
|
||||||
|
use signal_hook_tokio::Signals;
|
||||||
|
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
use crate::commands::CommandManager;
|
use crate::commands::CommandManager;
|
||||||
@@ -50,6 +54,27 @@ pub fn setup_logging(filename: &Path) -> Result<(), fern::InitError> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
async fn handle_signals(cursive_callback_sink: CbSink) {
|
||||||
|
let mut signals = Signals::new([SIGTERM, SIGHUP]).expect("could not register signal handler");
|
||||||
|
|
||||||
|
while let Some(signal) = signals.next().await {
|
||||||
|
info!("Caught {}, cleaning up and closing", signal);
|
||||||
|
match signal {
|
||||||
|
SIGTERM => {
|
||||||
|
cursive_callback_sink
|
||||||
|
.send(Box::new(|cursive| {
|
||||||
|
if let Some(data) = cursive.user_data::<UserData>().cloned() {
|
||||||
|
data.cmd.handle(cursive, Command::Quit);
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.expect("can't send callback to cursive");
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type UserData = Rc<UserDataInner>;
|
pub type UserData = Rc<UserDataInner>;
|
||||||
pub struct UserDataInner {
|
pub struct UserDataInner {
|
||||||
pub cmd: CommandManager,
|
pub cmd: CommandManager,
|
||||||
@@ -193,6 +218,14 @@ impl Application {
|
|||||||
|
|
||||||
cursive.add_fullscreen_layer(layout.with_name("main"));
|
cursive.add_fullscreen_layer(layout.with_name("main"));
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
let cursive_callback_sink = cursive.cb_sink().clone();
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
ASYNC_RUNTIME.get().unwrap().spawn(async {
|
||||||
|
handle_signals(cursive_callback_sink).await;
|
||||||
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
queue,
|
queue,
|
||||||
spotify,
|
spotify,
|
||||||
@@ -207,22 +240,9 @@ impl Application {
|
|||||||
|
|
||||||
/// Start the application and run the event loop.
|
/// Start the application and run the event loop.
|
||||||
pub fn run(&mut self) -> Result<(), String> {
|
pub fn run(&mut self) -> Result<(), String> {
|
||||||
#[cfg(unix)]
|
|
||||||
let mut signals =
|
|
||||||
Signals::new([SIGTERM, SIGHUP]).expect("could not register signal handler");
|
|
||||||
|
|
||||||
// cursive event loop
|
// cursive event loop
|
||||||
while self.cursive.is_running() {
|
while self.cursive.is_running() {
|
||||||
self.cursive.step();
|
self.cursive.step();
|
||||||
#[cfg(unix)]
|
|
||||||
for signal in signals.pending() {
|
|
||||||
if signal == SIGTERM || signal == SIGHUP {
|
|
||||||
info!("Caught {}, cleaning up and closing", signal);
|
|
||||||
if let Some(data) = self.cursive.user_data::<UserData>().cloned() {
|
|
||||||
data.cmd.handle(&mut self.cursive, Command::Quit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for event in self.event_manager.msg_iter() {
|
for event in self.event_manager.msg_iter() {
|
||||||
match event {
|
match event {
|
||||||
Event::Player(state) => {
|
Event::Player(state) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user