1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! 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())
    }
}