From 97f549cf5f3287ad0a4f37982d80641ed03cd6c6 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 12:42:01 +0100 Subject: [PATCH 1/8] Add daemonization. --- Cargo.lock | 9 ++++ Cargo.toml | 1 + parity/main.rs | 122 ++++++++++++++++++++++++++++++------------------- 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e9f57900..87a599f3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ version = "0.9.99" dependencies = [ "clippy 0.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.0.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", + "daemonize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "docopt_macros 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -108,6 +109,14 @@ dependencies = [ "winapi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "daemonize" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "docopt" version = "0.6.78" diff --git a/Cargo.toml b/Cargo.toml index c58cacf0d..828ed32e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" +daemonize = "0.2" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index 460922b64..d0bc05a08 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -25,11 +25,13 @@ extern crate rustc_serialize; extern crate ethcore_util as util; extern crate ethcore; extern crate ethsync; +#[macro_use] extern crate log as rlog; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; +extern crate daemonize; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -48,6 +50,7 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use target_info::Target; +use daemonize::{Daemonize}; docopt!(Args derive Debug, " Parity. Ethereum Client. @@ -55,12 +58,14 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or frontier, mainnet, morden, or testnet [default: frontier]. + or frontier, mainnet, morden, or testnet [default: frontier]. -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] + --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --no-bootstrap Don't bother trying to connect to any nodes initially. --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. @@ -136,6 +141,10 @@ impl Configuration { self.args.flag_db_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } + fn keys_path(&self) -> String { + self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + } + fn spec(&self) -> Spec { match self.args.flag_chain.as_ref() { "frontier" | "mainnet" => ethereum::new_frontier(), @@ -171,6 +180,71 @@ impl Configuration { (listen_address, public_address) } + + fn execute(&self) { + if self.args.flag_version { + print_version(); + return; + } + if self.args.cmd_daemon { + let daemonize = Daemonize::new() + .pid_file("/tmp/parity.pid") // Every method except `new` and `start` + .chown_pid_file(true) // is optional, see `Daemonize` documentation + .working_directory("/tmp") // for default behaviour. + .user("nobody") + .group("daemon") // Group name + .group(2) // Or group id + .privileged_action(|| "Executed before drop privileges"); + + match daemonize.start() { + Ok(_) => info!("Success, daemonized"), + Err(e) => { error!("{}", e); return; }, + } + } + self.execute_client(); + } + + fn execute_client(&self) { + // Setup logging + setup_log(&self.args.flag_logging); + // Raise fdlimit + unsafe { ::fdlimit::raise_fd_limit(); } + + let spec = self.spec(); + + // Configure network + let mut net_settings = NetworkConfiguration::new(); + net_settings.nat_enabled = self.args.flag_upnp; + net_settings.boot_nodes = self.init_nodes(&spec); + let (listen, public) = self.net_addresses(); + net_settings.listen_address = listen; + net_settings.public_address = public; + net_settings.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); + + // Build client + let mut service = ClientService::start(spec, net_settings, &Path::new(&self.path())).unwrap(); + let client = service.client().clone(); + client.configure_cache(self.args.flag_cache_pref_size, self.args.flag_cache_max_size); + + // Sync + let sync = EthSync::register(service.network(), client); + + // Setup rpc + if self.args.flag_jsonrpc { + setup_rpc_server(service.client(), sync.clone(), &self.args.flag_jsonrpc_url); + } + + // Register IO handler + let io_handler = Arc::new(ClientIoHandler { + client: service.client(), + info: Default::default(), + sync: sync + }); + service.io().register_handler(io_handler).expect("Error registering IO handler"); + + // Handle exit + wait_for_exit(&service); + } } fn wait_for_exit(client_service: &ClientService) { @@ -186,51 +260,7 @@ fn wait_for_exit(client_service: &ClientService) { } fn main() { - let conf = Configuration::parse(); - if conf.args.flag_version { - print_version(); - return; - } - - let spec = conf.spec(); - - // Setup logging - setup_log(&conf.args.flag_logging); - // Raise fdlimit - unsafe { ::fdlimit::raise_fd_limit(); } - - // Configure network - let mut net_settings = NetworkConfiguration::new(); - net_settings.nat_enabled = conf.args.flag_upnp; - net_settings.boot_nodes = conf.init_nodes(&spec); - let (listen, public) = conf.net_addresses(); - net_settings.listen_address = listen; - net_settings.public_address = public; - net_settings.use_secret = conf.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).expect("Invalid key string")); - - // Build client - let mut service = ClientService::start(spec, net_settings, &Path::new(&conf.path())).unwrap(); - let client = service.client().clone(); - client.configure_cache(conf.args.flag_cache_pref_size, conf.args.flag_cache_max_size); - - // Sync - let sync = EthSync::register(service.network(), client); - - // Setup rpc - if conf.args.flag_jsonrpc { - setup_rpc_server(service.client(), sync.clone(), &conf.args.flag_jsonrpc_url); - } - - // Register IO handler - let io_handler = Arc::new(ClientIoHandler { - client: service.client(), - info: Default::default(), - sync: sync - }); - service.io().register_handler(io_handler).expect("Error registering IO handler"); - - // Handle exit - wait_for_exit(&service); + Configuration::parse().execute(); } struct Informant { From ca353dd18e37fc7d2a25fd22927311ec1ebf8285 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:07:57 +0100 Subject: [PATCH 2/8] Remove daemonize feature. --- parity/main.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index d0bc05a08..8af61ca93 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -31,7 +31,6 @@ extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; -extern crate daemonize; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -50,7 +49,6 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use target_info::Target; -use daemonize::{Daemonize}; docopt!(Args derive Debug, " Parity. Ethereum Client. @@ -58,7 +56,6 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -186,21 +183,6 @@ impl Configuration { print_version(); return; } - if self.args.cmd_daemon { - let daemonize = Daemonize::new() - .pid_file("/tmp/parity.pid") // Every method except `new` and `start` - .chown_pid_file(true) // is optional, see `Daemonize` documentation - .working_directory("/tmp") // for default behaviour. - .user("nobody") - .group("daemon") // Group name - .group(2) // Or group id - .privileged_action(|| "Executed before drop privileges"); - - match daemonize.start() { - Ok(_) => info!("Success, daemonized"), - Err(e) => { error!("{}", e); return; }, - } - } self.execute_client(); } From 870731cb9fe76a0689c62cdcbda992801608c70c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:08:25 +0100 Subject: [PATCH 3/8] No need to bring in daemonize module. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 828ed32e7..c58cacf0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" -daemonize = "0.2" [features] default = ["rpc"] From 7f2acedf9fce9cc0cb0383bf6027d46ec7e0448e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:10:04 +0100 Subject: [PATCH 4/8] Reintroduce daemonize. --- Cargo.toml | 1 + parity/main.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index c58cacf0d..828ed32e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } target_info = "0.1" +daemonize = "0.2" [features] default = ["rpc"] diff --git a/parity/main.rs b/parity/main.rs index 8af61ca93..d0bc05a08 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -31,6 +31,7 @@ extern crate env_logger; extern crate ctrlc; extern crate fdlimit; extern crate target_info; +extern crate daemonize; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; @@ -49,6 +50,7 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use target_info::Target; +use daemonize::{Daemonize}; docopt!(Args derive Debug, " Parity. Ethereum Client. @@ -56,6 +58,7 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -183,6 +186,21 @@ impl Configuration { print_version(); return; } + if self.args.cmd_daemon { + let daemonize = Daemonize::new() + .pid_file("/tmp/parity.pid") // Every method except `new` and `start` + .chown_pid_file(true) // is optional, see `Daemonize` documentation + .working_directory("/tmp") // for default behaviour. + .user("nobody") + .group("daemon") // Group name + .group(2) // Or group id + .privileged_action(|| "Executed before drop privileges"); + + match daemonize.start() { + Ok(_) => info!("Success, daemonized"), + Err(e) => { error!("{}", e); return; }, + } + } self.execute_client(); } From c6bcd464c2689cac0e3860aa41f9e5bba3480da8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:54:18 +0100 Subject: [PATCH 5/8] Avoid changing user for daemonize. Just stick to the basics. --- parity/main.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index d0bc05a08..7e66fcbab 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -58,7 +58,7 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -187,19 +187,11 @@ impl Configuration { return; } if self.args.cmd_daemon { - let daemonize = Daemonize::new() - .pid_file("/tmp/parity.pid") // Every method except `new` and `start` - .chown_pid_file(true) // is optional, see `Daemonize` documentation - .working_directory("/tmp") // for default behaviour. - .user("nobody") - .group("daemon") // Group name - .group(2) // Or group id - .privileged_action(|| "Executed before drop privileges"); - - match daemonize.start() { - Ok(_) => info!("Success, daemonized"), - Err(e) => { error!("{}", e); return; }, - } + let daemonize = Daemonize::new().pid_file(self.args.arg_pid_file.clone()).chown_pid_file(true); + match daemonize.start() { + Ok(_) => info!("Daemonized"), + Err(e) => { error!("{}", e); return; }, + } } self.execute_client(); } From 379876341e208cf58aea388dc0fda427d722bb91 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 13:56:15 +0100 Subject: [PATCH 6/8] Correct alignment. --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 7e66fcbab..e557316c1 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -63,7 +63,7 @@ Usage: Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file - or frontier, mainnet, morden, or testnet [default: frontier]. + or frontier, mainnet, morden, or testnet [default: frontier]. -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] From 1447fb9d30e6f2ebeefd704b72d9f7980f880202 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 14:16:55 +0100 Subject: [PATCH 7/8] Switch to using non-macro ready for beta. --- parity/main.rs | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index e557316c1..50c9a78cb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -18,7 +18,6 @@ #![warn(missing_docs)] #![feature(plugin)] -#![plugin(docopt_macros)] #![plugin(clippy)] extern crate docopt; extern crate rustc_serialize; @@ -49,10 +48,11 @@ use ethcore::service::{ClientService, NetSyncMessage}; use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; +use docopt::Docopt; use target_info::Target; -use daemonize::{Daemonize}; +use daemonize::Daemonize; -docopt!(Args derive Debug, " +const USAGE: &'static str = " Parity. Ethereum Client. By Wood/Paronyan/Kotewicz/Drwięga/Volf. Copyright 2015, 2016 Ethcore (UK) Limited @@ -83,9 +83,31 @@ Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. -h --help Show this screen. -", flag_cache_pref_size: usize, flag_cache_max_size: usize, flag_address: Option, flag_node_key: Option); +"; -fn setup_log(init: &str) { +#[derive(Debug, RustcDecodable)] +struct Args { + cmd_daemon: bool, + arg_pid_file: String, + arg_enode: Vec, + flag_chain: String, + flag_db_path: String, + flag_keys_path: String, + flag_no_bootstrap: bool, + flag_listen_address: String, + flag_public_address: String, + flag_address: Option, + flag_upnp: bool, + flag_node_key: Option, + flag_cache_pref_size: usize, + flag_cache_max_size: usize, + flag_jsonrpc: bool, + flag_jsonrpc_url: String, + flag_logging: Option, + flag_version: bool, +} + +fn setup_log(init: &Option) { let mut builder = LogBuilder::new(); builder.filter(None, LogLevelFilter::Info); @@ -93,7 +115,9 @@ fn setup_log(init: &str) { builder.parse(&env::var("RUST_LOG").unwrap()); } - builder.parse(init); + if let Some(ref s) = *init { + builder.parse(s); + } builder.init().unwrap(); } @@ -133,7 +157,7 @@ struct Configuration { impl Configuration { fn parse() -> Self { Configuration { - args: Args::docopt().decode().unwrap_or_else(|e| e.exit()) + args: Docopt::new(USAGE).and_then(|d| d.decode()).unwrap_or_else(|e| e.exit()), } } From 7d75626e75b81bc3347039af9169cbc9d10be405 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 18 Feb 2016 14:28:24 +0100 Subject: [PATCH 8/8] Fix options. --- parity/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 50c9a78cb..077d92e54 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -58,7 +58,7 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] + parity daemon [options] [ --no-bootstrap | ... ] parity [options] [ --no-bootstrap | ... ] Options: @@ -182,7 +182,7 @@ impl Configuration { if self.args.flag_no_bootstrap { Vec::new() } else { match self.args.arg_enode.len() { 0 => spec.nodes().clone(), - _ => self.args.arg_enode.clone(), + _ => self.args.arg_enode.clone(), // TODO check format first. } } }