summaryrefslogtreecommitdiffhomepage
path: root/talpid_cli/src
diff options
context:
space:
mode:
Diffstat (limited to 'talpid_cli/src')
-rw-r--r--talpid_cli/src/cli.rs59
-rw-r--r--talpid_cli/src/main.rs72
2 files changed, 131 insertions, 0 deletions
diff --git a/talpid_cli/src/cli.rs b/talpid_cli/src/cli.rs
new file mode 100644
index 0000000000..c439a923ec
--- /dev/null
+++ b/talpid_cli/src/cli.rs
@@ -0,0 +1,59 @@
+use clap::{Arg, App, ArgMatches};
+use std::path::PathBuf;
+
+use talpid_core::net::RemoteAddr;
+
+static APP_AUTHOR: &'static str = "Mullvad";
+static APP_ABOUT: &'static str = "Run Talpid easily from the command line.";
+
+pub struct Args {
+ pub binary: String,
+ pub config: PathBuf,
+ pub remotes: Vec<RemoteAddr>,
+ pub verbosity: u64,
+}
+
+pub fn parse_args_or_exit() -> Args {
+ let matches = get_matches();
+ let remotes = values_t!(matches.values_of("remotes"), RemoteAddr).unwrap_or_else(|e| e.exit());
+ Args {
+ binary: matches.value_of("openvpn").unwrap().to_owned(),
+ config: PathBuf::from(matches.value_of("config").unwrap()),
+ remotes: remotes,
+ verbosity: matches.occurrences_of("verbose"),
+ }
+}
+
+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(APP_AUTHOR)
+ .about(APP_ABOUT)
+ .arg(Arg::with_name("openvpn")
+ .long("openvpn")
+ .help("Specify what OpenVPN binary to run")
+ .default_value("/usr/sbin/openvpn"))
+ .arg(Arg::with_name("config")
+ .short("c")
+ .long("config")
+ .help("Specify what config file to start OpenVPN with")
+ .default_value("./openvpn.conf"))
+ .arg(Arg::with_name("remotes")
+ .short("r")
+ .long("remotes")
+ .help("Configure what remote(s) to connect to. Accepts anything OpenVPN can use. \
+ Format: <address>:<port>")
+ .takes_value(true)
+ .multiple(true)
+ .required(true))
+ .arg(Arg::with_name("verbose")
+ .short("v")
+ .long("verbose")
+ .multiple(true)
+ .help("Sets the level of verbosity"))
+}
diff --git a/talpid_cli/src/main.rs b/talpid_cli/src/main.rs
new file mode 100644
index 0000000000..a174d7ed37
--- /dev/null
+++ b/talpid_cli/src/main.rs
@@ -0,0 +1,72 @@
+extern crate talpid_core;
+#[macro_use]
+extern crate clap;
+
+use std::io::{self, Read, Write};
+use std::sync::mpsc::{self, Receiver};
+use std::thread;
+
+use talpid_core::process::OpenVpnCommand;
+use talpid_core::process::monitor::{ChildMonitor, TransitionResult, ChildSpawner};
+
+mod cli;
+
+use cli::Args;
+
+/// Macro for printing to stderr. Will simply do nothing if the printing fails for some reason.
+macro_rules! eprintln {
+ ($($arg:tt)*) => (
+ use std::io::Write;
+ let _ = writeln!(&mut ::std::io::stderr(), $($arg)* );
+ )
+}
+
+fn main() {
+ let args = cli::parse_args_or_exit();
+
+ let command = create_openvpn_command(&args);
+ let monitor = ChildMonitor::new(command);
+ if let Err(e) = main_loop(monitor) {
+ eprintln!("OpenVPN failed: {}", e);
+ }
+}
+
+fn create_openvpn_command(args: &Args) -> OpenVpnCommand {
+ let mut command = OpenVpnCommand::new(&args.binary);
+ command.config(&args.config)
+ .remotes(&args.remotes[..])
+ .unwrap()
+ .pipe_output(args.verbosity > 0);
+
+ command
+}
+
+fn main_loop<S>(mut monitor: ChildMonitor<S>) -> TransitionResult<()>
+ where S: ChildSpawner
+{
+ loop {
+ let rx = start_monitor(&mut monitor)?;
+ let clean_exit = rx.recv().unwrap();
+ println!("Monitored process exited. clean: {}", clean_exit);
+ std::thread::sleep(std::time::Duration::from_millis(500));
+ }
+}
+
+fn start_monitor<S>(monitor: &mut ChildMonitor<S>) -> TransitionResult<Receiver<bool>>
+ where S: ChildSpawner
+{
+ let (tx, rx) = mpsc::channel();
+ let callback = move |clean| tx.send(clean).unwrap();
+ monitor.start(callback).map(|(stdout, stderr)| {
+ stdout.map(|stream| pass_io(stream, io::stdout()));
+ stderr.map(|stream| pass_io(stream, io::stderr()));
+ rx
+ })
+}
+
+fn pass_io<I, O>(mut input: I, mut output: O)
+ where I: Read + Send + 'static,
+ O: Write + Send + 'static
+{
+ thread::spawn(move || { io::copy(&mut input, &mut output).unwrap(); });
+}