From a3a06951ffca052cfc835c878277dca3b3e07dff Mon Sep 17 00:00:00 2001 From: Ignotus Peverell Date: Thu, 27 Apr 2017 22:07:25 -0700 Subject: [PATCH] Integrated clap for a better command line Allows for client, server and wallet subcommands. Processes the main necessary options for server mode right now. --- Cargo.toml | 2 + src/bin/grin.rs | 118 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 115 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86cb87cfd..af66a3105 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,8 @@ members = ["api", "chain", "core", "grin", "p2p", "store", "util"] [dependencies] grin_grin = { path = "./grin" } +clap = "^2.23.3" +daemonize = "^0.2.3" env_logger="^0.3.5" log = "^0.3" serde = "~0.9.10" diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 2dcc83ca8..1b5433411 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -14,6 +14,8 @@ //! Main for building the binary of a Grin peer-to-peer node. +extern crate clap; +extern crate daemonize; #[macro_use] extern crate log; extern crate env_logger; @@ -30,15 +32,121 @@ use std::io::Read; use std::fs::File; use std::time::Duration; +use clap::{Arg, App, SubCommand, ArgMatches}; +use daemonize::Daemonize; + fn main() { env_logger::init().unwrap(); - info!("Starting the Grin server..."); - grin::Server::start(read_config()).unwrap(); + let args = App::new("Grin") + .version("0.1") + .author("The Grin Team") + .about("Lightweight implementation of the MimbleWimble protocol.") - loop { - thread::sleep(Duration::from_secs(60)); - } + // specification of all the server commands and options + .subcommand(SubCommand::with_name("server") + .about("Control the Grin server") + .arg(Arg::with_name("port") + .short("p") + .long("port") + .help("Port to start the server on") + .takes_value(true)) + .arg(Arg::with_name("seed") + .short("s") + .long("seed") + .help("Override seed node(s) to connect to") + .takes_value(true) + .multiple(true)) + .arg(Arg::with_name("mine") + .short("m") + .long("mine") + .help("Starts the debugging mining loop")) + .arg(Arg::with_name("config") + .short("c") + .long("config") + .value_name("FILE.json") + .help("Sets a custom json configuration file") + .takes_value(true)) + .subcommand(SubCommand::with_name("start") + .about("Start the Grin server as a daemon")) + .subcommand(SubCommand::with_name("stop") + .about("Stop the Grin server daemon")) + .subcommand(SubCommand::with_name("run") + .about("Run the Grin server in this console"))) + + // specification of all the client commands and options + .subcommand(SubCommand::with_name("client") + .about("Communicates with the Grin server") + .subcommand(SubCommand::with_name("status") + .about("current status of the Grin chain"))) + .get_matches(); + + match args.subcommand() { + // server commands and options + ("server", Some(server_args)) => { + server_command(server_args); + }, + + // client commands and options + ("client", Some(client_args)) => { + match client_args.subcommand() { + ("status", _) => { + println!("status info..."); + }, + _ => panic!("Unknown client command, use 'grin help client' for details"), + } + } + + _ => panic!("Unknown command, use 'grin help' for a list of all commands"), + } +} + +/// Handles the server part of the command line, mostly running, starting and +/// stopping the Grin blockchain server. Processes all the command line arguments +/// to build a proper configuration and runs Grin with that configuration. +fn server_command(server_args: &ArgMatches) { + info!("Starting the Grin server..."); + + // configuration wrangling + let mut server_config = read_config(); + if let Some(port) = server_args.value_of("port") { + server_config.p2p_config.port = port.parse().unwrap(); + } + if server_args.is_present("mine") { + server_config.enable_mining = true; + } + if let Some(seeds) = server_args.values_of("seed") { + server_config.seeding_type = grin::Seeding::List(seeds.map(|s| s.to_string()).collect()); + } + + // start the server in the different run modes (interactive or daemon) + match server_args.subcommand() { + ("run", _) => { + grin::Server::start(server_config).unwrap(); + loop { + thread::sleep(Duration::from_secs(60)); + } + }, + ("start", _) => { + let daemonize = Daemonize::new() + .pid_file("/tmp/grin.pid") + .chown_pid_file(true) + .privileged_action(move || { + grin::Server::start(server_config.clone()).unwrap(); + loop { + thread::sleep(Duration::from_secs(60)); + } + }); + match daemonize.start() { + Ok(_) => info!("Grin server succesfully started."), + Err(e) => error!("Error starting: {}", e), + } + } + ("stop", _) => { + println!("TODO, just 'kill $pid' for now.") + } + _ => panic!("Unknown server command, use 'grin help server' for details"), + } } fn read_config() -> grin::ServerConfig {