summaryrefslogtreecommitdiffhomepage
path: root/mullvad_cli/src
diff options
context:
space:
mode:
authorLinus Färnstrand <linus@mullvad.net>2017-07-07 13:48:12 +0200
committerLinus Färnstrand <linus@mullvad.net>2017-07-07 13:52:13 +0200
commit0aef8955e6a67849d9559d2bae82a1ed2c2694ba (patch)
tree2589c850dae265d65f830291f60bbc6d39e1881e /mullvad_cli/src
parentce4cb31d0ce12f81dd2c5ed32be75725e7ee7072 (diff)
downloadmullvadvpn-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.rs24
-rw-r--r--mullvad_cli/src/cmds/account.rs56
-rw-r--r--mullvad_cli/src/cmds/mod.rs17
-rw-r--r--mullvad_cli/src/main.rs65
-rw-r--r--mullvad_cli/src/rpc.rs29
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");
+}