wurl 0.1.0

WebSocket CLI for developers
Documentation
#[macro_use]
extern crate clap;
#[macro_use]
extern crate log;
extern crate rprompt;
extern crate stderrlog;
extern crate ws;
extern crate wurl;

mod app;
mod messages;

use messages::{parse_message, Kind};
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
use std::error::Error;
use rprompt::read_reply;
use ws::CloseCode;
use app::build_app;
use wurl::util::options::{Options, Show};
use wurl::network::ws::connect;

fn main() {
    let mut app = build_app();
    let matches = app.clone().get_matches();
    let mut opts = Options::default();

    opts.echo = matches.is_present("echo");
    opts.print_headers = matches.is_present("include");
    opts.silent = matches.is_present("silent");

    if let Ok(show_control_frames) = value_t!(matches, "show_control_frames", Show) {
        opts.show_control_frames = show_control_frames;
    }

    if let Ok(url) = value_t!(matches, "url", String) {
        opts.url = url;
    }

    if let Ok(headers) = values_t!(matches, "headers", String) {
        opts.headers = headers;
    }

    if opts.url.is_empty() {
        app.print_help().expect("Failed to print help message");
        exit(1);
    }

    stderrlog::new()
        .module(module_path!())
        .quiet(opts.silent)
        .verbosity(matches.occurrences_of("verbose") as usize)
        .init()
        .expect("Failed to instantiate logger");

    info!("Parsed options as: {:?}", opts);

    let sender = connect(opts).unwrap_or_else(|error| {
        eprintln!("Failed to connect to WebSocket server: {}", error);
        exit(1);
    });

    loop {
        match read_reply() {
            Ok(input) => {
                let message = parse_message(input);
                trace!("Message: {:?}", message);

                if let Err(error) = message {
                    eprintln!("Error: {:?}", error.description());
                    continue;
                }

                let message = message.unwrap();

                match message.kind {
                    Kind::Message => sender
                        .send(message.message.expect("Message did not contain a message"))
                        .expect("Failed to send WebSocket message"),
                    Kind::Ping => sender
                        .ping(Vec::new())
                        .expect("Failed to send ping message"),
                    Kind::Pong => sender
                        .pong(Vec::new())
                        .expect("Failed to send ping message"),
                    Kind::Close => sender
                        .close(CloseCode::from(
                            message
                                .code
                                .expect("Close control frame did not containt a cause code"),
                        ))
                        .expect("Failed to send ping message"),
                }
            }
            Err(error) => match error.kind() {
                std::io::ErrorKind::UnexpectedEof => {
                    trace!("Encounteded EOF in stdin, sleeping");
                    sleep(Duration::from_secs(1));
                }
                _ => {
                    warn!("Error: {:?}", error);
                    eprintln!("error: {}", error);
                    exit(2);
                }
            },
        }
    }
}