libeko 0.1.5

Create a command line interface binary with some common dependencies ((clap || docopt) and error_chain)
Documentation
//! curl implementation for sending `Echo Event`
use curl::easy::{Easy, List};
use echo::event::Message;
use error::Result;
use serde_json;
use std::io::Read;
use {EchoEventClient, EchoSearchClient};

/// A curl based `Echo` client.
#[derive(Debug)]
pub struct Client {
    /// 'curl' easy API
    easy: Easy,
    /// `Echo` rest endpoint
    url: String,
}

impl Client {
    /// Create a new curl based event sender.
    pub fn new() -> Result<Self> {
        let mut list = List::new();
        list.append("Content-Type: application/json")?;
        list.append(&format!(
            "User-Agent: {}/{}",
            env!("CARGO_PKG_NAME"),
            env!("CARGO_PKG_VERSION")
        ))?;
        list.append("Expect: ")?;

        let mut easy = Easy::new();
        easy.post(true)?;
        easy.http_headers(list)?;

        Ok(Self {
            easy,
            url: Default::default(),
        })
    }

    /// Set the endpoint url.
    pub fn set_url(&mut self, url: &str) -> Result<&mut Self> {
        self.easy.url(url)?;
        Ok(self)
    }

    /// Set the verbose curl flag.
    pub fn set_verbose(&mut self, verbose: bool) -> Result<&mut Self> {
        self.easy.verbose(verbose)?;
        Ok(self)
    }

    /// Set the username (i.e. for Basic Authentication)
    pub fn set_username(&mut self, username: &str) -> Result<&mut Self> {
        self.easy.username(username)?;
        Ok(self)
    }

    /// Set the password (i.e. for Basic Authentication)
    pub fn set_password(&mut self, password: &str) -> Result<&mut Self> {
        self.easy.password(password)?;
        Ok(self)
    }
}

impl EchoEventClient for Client {
    fn send_event(&mut self, messages: &[Message]) -> Result<()> {
        let mut messages_vec = &serde_json::to_vec(&messages)?[..];
        self.easy.post_field_size(messages_vec.len() as u64)?;

        {
            let mut transfer = self.easy.transfer();
            transfer.read_function(|into| Ok(messages_vec.read(into).unwrap_or(0)))?;
            transfer.perform()?;
        }

        Ok(())
    }
}

impl EchoSearchClient for Client {
    fn search(&mut self, search: &str) -> Result<String> {
        let mut search_bytes = search.as_bytes();
        self.easy.post_field_size(search_bytes.len() as u64)?;

        let mut dst = Vec::new();

        {
            let mut transfer = self.easy.transfer();
            transfer.write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })?;
            transfer.read_function(|into| Ok(search_bytes.read(into).unwrap_or(0)))?;
            transfer.perform()?;
        }

        Ok(String::from_utf8_lossy(&dst).to_string())
    }

    fn scroll(&mut self, scroll: &str) -> Result<String> {
        let mut scroll_bytes = scroll.as_bytes();
        self.easy.post_field_size(scroll_bytes.len() as u64)?;

        let mut dst = Vec::new();

        {
            let mut transfer = self.easy.transfer();
            transfer.write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })?;
            transfer.read_function(|into| Ok(scroll_bytes.read(into).unwrap_or(0)))?;
            transfer.perform()?;
        }

        Ok(String::from_utf8_lossy(&dst).to_string())
    }
}