Просмотр исходного кода

faucetd: Remove ctrlc and introduce signal-hook.

parazyd 3 лет назад
Родитель
Сommit
ef86063e59
3 измененных файлов с 51 добавлено и 17 удалено
  1. 4 3
      Cargo.lock
  2. 2 1
      bin/faucetd/Cargo.toml
  3. 45 13
      bin/faucetd/src/main.rs

+ 4 - 3
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",

+ 2 - 1
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"

+ 45 - 13
bin/faucetd/src/main.rs

@@ -16,9 +16,13 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-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<Mutex<HashMap<[u8; 32], i64>>>, 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<smol::Executor<'_>>) -> 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<smol::Executor<'_>>) -> 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?;