|
|
@@ -120,3 +120,97 @@ macro_rules! cli_desc {
|
|
|
Box::leak(desc.into_boxed_str()) as &'static str
|
|
|
}};
|
|
|
}
|
|
|
+
|
|
|
+/// This macro is used for a standard way of daemonizing darkfi binaries
|
|
|
+/// with TOML config file configuration, and argument parsing. It also
|
|
|
+/// spawns a multithreaded async executor and passes it into the given
|
|
|
+/// function.
|
|
|
+///
|
|
|
+/// The Cargo.toml dependencies needed for this are:
|
|
|
+/// ```text
|
|
|
+/// async-channel = "1.6.1"
|
|
|
+/// async-executor = "1.4.1"
|
|
|
+/// async-std = "1.11.0"
|
|
|
+/// darkfi = { path = "../../", features = ["util"] }
|
|
|
+/// easy-parallel = "3.2.0"
|
|
|
+/// futures-lite = "1.12.0"
|
|
|
+/// simplelog = "0.12.0-alpha1"
|
|
|
+///
|
|
|
+/// # Argument parsing
|
|
|
+/// serde = "1.0.136"
|
|
|
+/// serde_derive = "1.0.136"
|
|
|
+/// structopt = "0.3.26"
|
|
|
+/// structopt-toml = "0.5.0"
|
|
|
+/// ```
|
|
|
+///
|
|
|
+/// Example usage:
|
|
|
+/// ```text
|
|
|
+/// use async_executor::Executor;
|
|
|
+/// use async_std::sync::Arc;
|
|
|
+/// use easy_parallel::Parallel;
|
|
|
+/// use futures_lite::future;
|
|
|
+/// use simplelog::{ColorChoice, TermLogger, TerminalMode};
|
|
|
+/// use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml};
|
|
|
+///
|
|
|
+/// use darkfi::{
|
|
|
+/// async_daemonize, cli_desc,
|
|
|
+/// util::{
|
|
|
+/// cli::{log_config, spawn_config},
|
|
|
+/// path::get_config_path,
|
|
|
+/// },
|
|
|
+/// Result,
|
|
|
+/// };
|
|
|
+///
|
|
|
+/// const CONFIG_FILE: &str = "daemond_config.toml";
|
|
|
+/// const CONFIG_FILE_CONTENTS: &str = include_str!("../daemond_config.toml");
|
|
|
+///
|
|
|
+/// #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
|
|
|
+/// #[serde(default)]
|
|
|
+/// #[structopt(name = "daemond", about = cli_desc!())]
|
|
|
+/// struct Args {
|
|
|
+/// #[structopt(short, long)]
|
|
|
+/// /// Configuration file to use
|
|
|
+/// config: Option<String>,
|
|
|
+///
|
|
|
+/// #[structopt(short, parse(from_occurrences))]
|
|
|
+/// /// Increase verbosity (-vvv supported)
|
|
|
+/// verbose: u8,
|
|
|
+/// }
|
|
|
+///
|
|
|
+/// async_daemonize!(realmain);
|
|
|
+/// async fn realmain(args: Args, ex: Arc<Executor<'_>>) -> Result<()> {
|
|
|
+/// println!("Hello, world!");
|
|
|
+/// Ok(())
|
|
|
+/// }
|
|
|
+/// ```
|
|
|
+#[macro_export]
|
|
|
+macro_rules! async_daemonize {
|
|
|
+ ($realmain:ident) => {
|
|
|
+ fn main() -> Result<()> {
|
|
|
+ let args = Args::from_args_with_toml("").unwrap();
|
|
|
+ let cfg_path = get_config_path(args.config, CONFIG_FILE)?;
|
|
|
+ spawn_config(&cfg_path, CONFIG_FILE_CONTENTS.as_bytes())?;
|
|
|
+ let args = Args::from_args_with_toml(&std::fs::read_to_string(cfg_path)?).unwrap();
|
|
|
+
|
|
|
+ let (lvl, conf) = log_config(args.verbose.into())?;
|
|
|
+ TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
|
|
|
+
|
|
|
+ // https://docs.rs/smol/latest/smol/struct.Executor.html#examples
|
|
|
+ let ex = Arc::new(Executor::new());
|
|
|
+ let (signal, shutdown) = async_channel::unbounded::<()>();
|
|
|
+ let (_, result) = Parallel::new()
|
|
|
+ // Run four executor threads
|
|
|
+ .each(0..4, |_| future::block_on(ex.run(shutdown.recv())))
|
|
|
+ // Run the main future on the current thread.
|
|
|
+ .finish(|| {
|
|
|
+ future::block_on(async {
|
|
|
+ $realmain(args, ex.clone()).await?;
|
|
|
+ drop(signal);
|
|
|
+ Ok::<(), darkfi::Error>(())
|
|
|
+ })
|
|
|
+ });
|
|
|
+
|
|
|
+ result
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|