diff --git a/Cargo.lock b/Cargo.lock index 55d8b18f..1e0726d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,6 +541,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "daemonize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8bfdaacb3c887a54d41bdf48d3af8873b3f5566469f8ba21b92057509f116e" +dependencies = [ + "libc", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -691,7 +700,7 @@ dependencies = [ "log", "rand 0.8.5", "rustreexo", - "secp256k1 0.27.0", + "secp256k1 0.28.2", "serde", "serde_json", "sha2", @@ -811,6 +820,7 @@ dependencies = [ "chrono", "clap", "ctrlc", + "daemonize", "dirs", "fern", "floresta-chain", diff --git a/README.md b/README.md index eb7691c2..88318fa3 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,12 @@ After building, florestad and floresta-cli will be available in the target direc florestad ``` +You may run it as a background process with the `--daemon` flag. + +```bash +florestad --daemon +``` + This will start the full node, and you can connect to it with an Electrum wallet or with the `floresta-cli` tool. ```bash diff --git a/florestad/Cargo.toml b/florestad/Cargo.toml index 6fe67e1c..ab4c7f93 100644 --- a/florestad/Cargo.toml +++ b/florestad/Cargo.toml @@ -38,6 +38,9 @@ jsonrpc-core-client = { version = "18.0.0", features = [ zmq = { version = "0.10.0", optional = true } latest = "0.1.1" +[target.'cfg(unix)'.dependencies] +daemonize = { version = "0.5.0" } + [lib] name = "florestad" path = "src/lib.rs" diff --git a/florestad/src/cli.rs b/florestad/src/cli.rs index 8526edc4..e8b1526f 100644 --- a/florestad/src/cli.rs +++ b/florestad/src/cli.rs @@ -70,7 +70,7 @@ pub struct Cli { /// Option for saving log into data_Dir /// /// if set, log will be saved into $DATA_DIR/output.log. - pub log_file: bool, + pub log_to_file: bool, #[arg(long, value_name = "PATH")] /// Where should we store data. This is the directory where we'll store the chainstate, @@ -161,4 +161,18 @@ pub struct Cli { /// trust in the developer that the utreexo state is correct. Everything after the assumed /// height will be fully validated. pub assume_utreexo: bool, + + #[cfg(unix)] + #[arg(long, default_value = "false")] + /// Whether we should run as a daemon + pub daemon: bool, + + #[cfg(unix)] + #[arg(long, value_name = "FILE", requires = "daemon")] + /// A file to write the process id to + /// + /// In case you're using the daemon option, and you want to know the process id, you can + /// write it to a file. This option should be an absolute path to a file. Usually, you'd + /// write it to $DATA_DIR/florestad.pid + pub pid_file: Option, } diff --git a/florestad/src/florestad.rs b/florestad/src/florestad.rs index 0625140b..6cbe708c 100644 --- a/florestad/src/florestad.rs +++ b/florestad/src/florestad.rs @@ -210,7 +210,6 @@ impl Florestad { }) }) .unwrap_or("floresta".into()); - let data_dir = match self.config.network { crate::Network::Bitcoin => data_dir, crate::Network::Signet => data_dir + "/signet/", diff --git a/florestad/src/main.rs b/florestad/src/main.rs index 90826074..86e933db 100644 --- a/florestad/src/main.rs +++ b/florestad/src/main.rs @@ -23,6 +23,8 @@ use std::time::Duration; use clap::Parser; use cli::Cli; +#[cfg(unix)] +use daemonize::Daemonize; use florestad::Config; use florestad::Florestad; use futures::executor::block_on; @@ -35,7 +37,7 @@ fn main() { let config = Config { network: params.network.into(), debug: params.debug, - data_dir: params.data_dir, + data_dir: params.data_dir.clone(), cfilters: params.cfilters, proxy: params.proxy, rescan: params.rescan, @@ -43,7 +45,10 @@ fn main() { connect: params.connect, wallet_xpub: params.wallet_xpub, config_file: params.config_file, - log_to_file: params.log_file, + #[cfg(unix)] + log_to_file: params.log_to_file || params.daemon, + #[cfg(not(unix))] + log_to_file: params.log_to_file, assume_valid: params.assume_valid, log_to_stdout: true, json_rpc_address: params.rpc_address, @@ -53,6 +58,16 @@ fn main() { user_agent: format!("/Floresta:{}/", env!("GIT_DESCRIBE")), assumeutreexo_value: None, }; + + #[cfg(unix)] + if params.daemon { + let mut daemon = Daemonize::new(); + if let Some(pid_file) = params.pid_file { + daemon = daemon.pid_file(pid_file); + } + daemon.start().expect("Failed to daemonize"); + } + let _rt = tokio::runtime::Builder::new_multi_thread() .enable_all() .worker_threads(4)