Writing a daemon

DarkFi consists of many seperate daemons communicating with each other. To run the p2p network, we'll need to implement our own daemon. So we'll start building dchat by creating a daemon that we call dchatd.

To do this, we'll make use of a DarkFi macro called async_daemonize.

async_daemonizeis the standard way of daemonizing darkfi binaries. It implements TOML config file configuration, argument parsing and a multithreaded async executor that can be passed into the given function.

We use async_daemonize as follows:

use darkfi::{async_daemonize, cli_desc, Result}; use smol::stream::StreamExt; use structopt_toml::{serde::Deserialize, structopt::StructOpt, StructOptToml}; const CONFIG_FILE: &str = "dchatd_config.toml"; const CONFIG_FILE_CONTENTS: &str = include_str!("../dchatd_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, long)] /// Set log file to ouput into log: Option<String>, #[structopt(short, parse(from_occurrences))] /// Increase verbosity (-vvv supported) verbose: u8, } async_daemonize!(realmain); async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> { println!("Hello, world!"); Ok(()) }

Behind the scenes, async_daemonize uses structopt and structopt_toml crates to build command line arguments as a struct called Args. It spins up a async executor using parallel threads, and implements signal handling to properly terminate the daemon on receipt of a stop signal.

async_daemonize allow us to spawn the config data we specify at CONFIG_FILE_CONTENTS into a directory either specified using the command-line flag --config, or in the default darkfi config directory.

async_daemonize also implements logging that will output different levels of debug info to the terminal, or to both the terminal and a log file if a log file is specified.