diff --git a/Cargo.lock b/Cargo.lock index e05146185..8f02c75b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1730,7 +1730,6 @@ dependencies = [ "async-trait", "blake3", "chrono", - "ctrlc", "darkfi", "darkfi-money-contract", "darkfi-sdk", @@ -1740,6 +1739,8 @@ dependencies = [ "rand", "serde", "serde_json", + "signal-hook", + "signal-hook-async-std", "simplelog", "sled", "smol", @@ -3654,9 +3655,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" dependencies = [ "libc", "signal-hook-registry", diff --git a/bin/faucetd/Cargo.toml b/bin/faucetd/Cargo.toml index 27002c951..504e8d3da 100644 --- a/bin/faucetd/Cargo.toml +++ b/bin/faucetd/Cargo.toml @@ -13,7 +13,6 @@ async-std = "1.12.0" async-trait = "0.1.64" blake3 = "1.3.3" chrono = "0.4.23" -ctrlc = { version = "3.2.4", features = ["termination"] } darkfi = {path = "../../", features = ["blockchain", "wallet", "rpc", "net", "zkas"]} darkfi-serial = {path = "../../src/serial"} darkfi-sdk = {path = "../../src/sdk"} @@ -22,6 +21,8 @@ easy-parallel = "3.2.0" log = "0.4.17" rand = "0.8.5" serde_json = "1.0.91" +signal-hook = "0.3.15" +signal-hook-async-std = "0.2.2" simplelog = "0.12.0" sled = "0.34.7" smol = "1.3.0" diff --git a/bin/faucetd/src/main.rs b/bin/faucetd/src/main.rs index 51f2d22da..620bfe4a1 100644 --- a/bin/faucetd/src/main.rs +++ b/bin/faucetd/src/main.rs @@ -16,9 +16,13 @@ * along with this program. If not, see . */ -use std::{collections::HashMap, str::FromStr}; +use std::{collections::HashMap, path::PathBuf, str::FromStr}; -use async_std::sync::{Arc, Mutex, RwLock}; +use async_std::{ + stream::StreamExt, + sync::{Arc, Mutex, RwLock}, + task, +}; use async_trait::async_trait; use chrono::Utc; use darkfi::{ @@ -47,6 +51,8 @@ use darkfi_serial::{deserialize, serialize, Encodable}; use log::{debug, error, info}; use rand::rngs::OsRng; use serde_json::{json, Value}; +use signal_hook::consts::{SIGHUP, SIGINT, SIGQUIT, SIGTERM}; +use signal_hook_async_std::Signals; use sqlx::Row; use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml}; use url::Url; @@ -72,7 +78,11 @@ use darkfi::{ }, server::{listen_and_serve, RequestHandler}, }, - util::{async_util::sleep, parse::decode_base10, path::expand_path}, + util::{ + async_util::sleep, + parse::decode_base10, + path::{expand_path, get_config_path}, + }, wallet::{walletdb::init_wallet, WalletPtr}, Error, Result, }; @@ -512,16 +522,36 @@ async fn prune_airdrop_map(map: Arc>>, timeout: i64 } } +async fn handle_signals( + mut signals: Signals, + _cfg_path: PathBuf, + term_tx: smol::channel::Sender<()>, +) { + debug!("Started signal handler"); + while let Some(signal) = signals.next().await { + match signal { + SIGHUP => { + info!("Caught SIGHUP"); + } + + SIGTERM | SIGINT | SIGQUIT => { + term_tx.send(()).await.unwrap(); + } + + _ => unreachable!(), + } + } +} + async_daemonize!(realmain); async fn realmain(args: Args, ex: Arc>) -> Result<()> { - // We use this handler to block this function after detaching all - // tasks, and to catch a shutdown signal, where we can clean up and - // exit gracefully. - let (signal, shutdown) = smol::channel::bounded::<()>(1); - ctrlc::set_handler(move || { - async_std::task::block_on(signal.send(())).unwrap(); - }) - .unwrap(); + let cfg_path = get_config_path(args.config, CONFIG_FILE)?; + + // Signal handling for config reload and graceful termination. + let signals = Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT])?; + let handle = signals.handle(); + let (term_tx, term_rx) = smol::channel::bounded::<()>(1); + let signals_task = task::spawn(handle_signals(signals, cfg_path.clone(), term_tx)); // Initialize or load wallet let wallet = init_wallet(&args.wallet_path, &args.wallet_pass).await?; @@ -653,10 +683,12 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { Err(e) => error!("Failed syncing blockchain: {}", e), } - // Wait for SIGINT - shutdown.recv().await?; + // Wait for termination signal + term_rx.recv().await?; print!("\r"); info!("Caught termination signal, cleaning up and exiting..."); + handle.close(); + signals_task.await; info!("Flushing database..."); let flushed_bytes = sled_db.flush_async().await?;