diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-07-07 13:48:12 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-07-07 13:52:13 +0200 |
| commit | 0aef8955e6a67849d9559d2bae82a1ed2c2694ba (patch) | |
| tree | 2589c850dae265d65f830291f60bbc6d39e1881e /mullvad_cli/src | |
| parent | ce4cb31d0ce12f81dd2c5ed32be75725e7ee7072 (diff) | |
| download | mullvadvpn-0aef8955e6a67849d9559d2bae82a1ed2c2694ba.tar.xz mullvadvpn-0aef8955e6a67849d9559d2bae82a1ed2c2694ba.zip | |
Clean up CLI code with better subcommand structure
Diffstat (limited to 'mullvad_cli/src')
| -rw-r--r-- | mullvad_cli/src/cli.rs | 24 | ||||
| -rw-r--r-- | mullvad_cli/src/cmds/account.rs | 56 | ||||
| -rw-r--r-- | mullvad_cli/src/cmds/mod.rs | 17 | ||||
| -rw-r--r-- | mullvad_cli/src/main.rs | 65 | ||||
| -rw-r--r-- | mullvad_cli/src/rpc.rs | 29 |
5 files changed, 122 insertions, 69 deletions
diff --git a/mullvad_cli/src/cli.rs b/mullvad_cli/src/cli.rs deleted file mode 100644 index c21e7f1562..0000000000 --- a/mullvad_cli/src/cli.rs +++ /dev/null @@ -1,24 +0,0 @@ -use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; - -pub fn get_matches() -> ArgMatches<'static> { - let app = create_app(); - app.clone().get_matches() -} - -fn create_app() -> App<'static, 'static> { - App::new(crate_name!()) - .version(crate_version!()) - .author(crate_authors!()) - .about(crate_description!()) - .setting(AppSettings::SubcommandRequired) - .subcommand(SubCommand::with_name("account") - .about("Control and display information about the configured Mullvad account") - .setting(AppSettings::SubcommandRequired) - .subcommand(SubCommand::with_name("set") - .about("Change the Mullvad account") - .arg(Arg::with_name("token") - .help("The Mullvad account token to configure the daemon with") - .required(true))) - .subcommand(SubCommand::with_name("get") - .about("Display information about the currently configured account"))) -} diff --git a/mullvad_cli/src/cmds/account.rs b/mullvad_cli/src/cmds/account.rs new file mode 100644 index 0000000000..bb4d75055f --- /dev/null +++ b/mullvad_cli/src/cmds/account.rs @@ -0,0 +1,56 @@ +use Command; +use Result; +use clap; +use rpc; +use serde_json; + +pub struct Account; + +impl Command for Account { + fn name(&self) -> &'static str { + "account" + } + + fn clap_subcommand(&self) -> clap::App<'static, 'static> { + clap::SubCommand::with_name(self.name()) + .about("Control and display information about your Mullvad account") + .setting(clap::AppSettings::SubcommandRequired) + .subcommand(clap::SubCommand::with_name("set") + .about("Change account") + .arg(clap::Arg::with_name("token") + .help("The Mullvad account token to configure the client with") + .required(true))) + .subcommand(clap::SubCommand::with_name("get") + .about("Display information about the currently configured account")) + } + + fn run(&self, matches: &clap::ArgMatches) -> Result<()> { + if let Some(set_matches) = matches.subcommand_matches("set") { + self.set(set_matches) + } else if let Some(_matches) = matches.subcommand_matches("get") { + self.get() + } else { + unreachable!("No account command given"); + } + } +} + +impl Account { + fn set(&self, matches: &clap::ArgMatches) -> Result<()> { + let token = value_t_or_exit!(matches.value_of("token"), String); + rpc::call("set_account", &[&token]).map( + |_| { + println!("Mullvad account {} set", token); + }, + ) + } + + fn get(&self) -> Result<()> { + match rpc::call("get_account", &[] as &[u8; 0])? { + serde_json::Value::String(token) => println!("Mullvad account: {:?}", token), + serde_json::Value::Null => println!("No account configured"), + _ => bail!("Unable to fetch account token"), + } + Ok(()) + } +} diff --git a/mullvad_cli/src/cmds/mod.rs b/mullvad_cli/src/cmds/mod.rs new file mode 100644 index 0000000000..3f881bcfb8 --- /dev/null +++ b/mullvad_cli/src/cmds/mod.rs @@ -0,0 +1,17 @@ +use Command; +use std::collections::HashMap; + +mod account; +pub use self::account::*; + +/// Returns a map of all available subcommands with their name as key. +pub fn get_commands() -> HashMap<&'static str, Box<Command>> { + let commands = vec![Box::new(Account) as Box<Command>]; + let mut map = HashMap::new(); + for cmd in commands { + if let Some(_) = map.insert(cmd.name(), cmd) { + panic!("Multiple commands with the same name"); + } + } + map +} diff --git a/mullvad_cli/src/main.rs b/mullvad_cli/src/main.rs index 0d87173418..3d49be3964 100644 --- a/mullvad_cli/src/main.rs +++ b/mullvad_cli/src/main.rs @@ -12,10 +12,8 @@ extern crate env_logger; extern crate serde; extern crate serde_json; -use std::fs::File; -use std::io::Read; - -mod cli; +mod rpc; +mod cmds; error_chain!{} @@ -25,51 +23,28 @@ quick_main!(run); fn run() -> Result<()> { env_logger::init().chain_err(|| "Failed to bootstrap logging system")?; - let matches = cli::get_matches(); - if let Some(matches) = matches.subcommand_matches("account") { - cmd_account(matches) - } else { - unreachable!("No subcommand matches.") - } -} + let commands = cmds::get_commands(); -fn cmd_account(matches: &clap::ArgMatches) -> Result<()> { - if let Some(matches) = matches.subcommand_matches("set") { - let token = matches.value_of("token").unwrap(); - call_rpc("set_account", &[token]).map( - |_| { - println!("Mullvad account {} set", token); - }, - ) - } else if let Some(_matches) = matches.subcommand_matches("get") { - match call_rpc("get_account", &[] as &[u8; 0])? { - serde_json::Value::String(token) => println!("Mullvad account: {:?}", token), - serde_json::Value::Null => println!("No account configured"), - _ => bail!("Unable to fetch account token"), - } - Ok(()) + let app = clap::App::new(crate_name!()) + .version(crate_version!()) + .author(crate_authors!()) + .about(crate_description!()) + .setting(clap::AppSettings::SubcommandRequired) + .subcommands(commands.values().map(|cmd| cmd.clap_subcommand())); + + let app_matches = app.get_matches(); + let (subcommand_name, subcommand_matches) = app_matches.subcommand(); + if let Some(cmd) = commands.get(subcommand_name) { + cmd.run(subcommand_matches.expect("No command matched")) } else { - unreachable!("No account command given"); + unreachable!("No command matched"); } } -fn call_rpc<T>(method: &str, args: &T) -> Result<serde_json::Value> - where T: serde::Serialize -{ - let address = read_rpc_address()?; - info!("Using RPC address {}", address); - let mut rpc_client = talpid_ipc::WsIpcClient::new(address) - .chain_err(|| "Unable to create RPC client")?; - rpc_client.call(method, args).chain_err(|| "Unable to call RPC method") -} +pub trait Command { + fn name(&self) -> &'static str; -fn read_rpc_address() -> Result<String> { - for path in &["./.mullvad_rpc_address", "../.mullvad_rpc_address"] { - debug!("Trying to read RPC address at {}", path); - let mut address = String::new(); - if let Ok(_) = File::open(path).and_then(|mut file| file.read_to_string(&mut address)) { - return Ok(address); - } - } - bail!("Unable to read RPC address"); + fn clap_subcommand(&self) -> clap::App<'static, 'static>; + + fn run(&self, matches: &clap::ArgMatches) -> Result<()>; } diff --git a/mullvad_cli/src/rpc.rs b/mullvad_cli/src/rpc.rs new file mode 100644 index 0000000000..11a6da33fb --- /dev/null +++ b/mullvad_cli/src/rpc.rs @@ -0,0 +1,29 @@ + + +use {Result, ResultExt}; +use serde; +use serde_json; +use std::fs::File; +use std::io::Read; +use talpid_ipc::WsIpcClient; + +pub fn call<T>(method: &str, args: &T) -> Result<serde_json::Value> + where T: serde::Serialize +{ + let address = read_rpc_address()?; + info!("Using RPC address {}", address); + let mut rpc_client = WsIpcClient::new(address) + .chain_err(|| "Unable to create RPC client")?; + rpc_client.call(method, args).chain_err(|| "Unable to call RPC method") +} + +fn read_rpc_address() -> Result<String> { + for path in &["./.mullvad_rpc_address", "../.mullvad_rpc_address"] { + debug!("Trying to read RPC address at {}", path); + let mut address = String::new(); + if let Ok(_) = File::open(path).and_then(|mut file| file.read_to_string(&mut address)) { + return Ok(address); + } + } + bail!("Unable to read RPC address"); +} |
