<commit_before>//! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null

use std::fmt;
use std::ops;
use std::ptr;
use winapi::Interface;
use winapi::ctypes::c_void;
use winapi::shared::guiddef::GUID;
use winapi::shared::winerror::HRESULT;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::unknwnbase::IUnknown;

pub type HResult<T> = Result<T, HResultError>;

/// An error code returned by a Windows API.
pub struct HResultError(HRESULT);

impl fmt::Debug for HResultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:08X}", self.0 as u32)
    }
}

impl From<HRESULT> for HResultError {
    fn from(h: HRESULT) -> Self {
        HResultError(h)
    }
}

pub trait ToResult: Sized {
    fn to_result(self) -> HResult<()>;
}

impl ToResult for HRESULT {
    fn to_result(self) -> HResult<()> {
        if SUCCEEDED(self) {
            Ok(())
        } else {
            Err(HResultError(self))
        }
    }
}

pub fn as_ptr<T>(x: &T) -> *mut T {
    x as *const T as _
}

/// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs
#[derive(PartialEq, Debug)]
pub struct ComPtr<T>(*mut T) where T: Interface;

impl<T> ComPtr<T> where T: Interface {
    /// Creates a `ComPtr` to wrap a raw pointer.
    /// It takes ownership over the pointer which means it does __not__ call `AddRef`.
    /// `T` __must__ be a COM interface that inherits from `IUnknown`.
    pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
        assert!(!ptr.is_null());
        ComPtr(ptr)
    }

    /// For use with APIs that take an interface UUID and
    /// "return" a new COM object through a `*mut *mut c_void` out-parameter.
    pub unsafe fn new_with_uuid<F>(f: F) -> HResult<Self>
        where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT
    {
        Self::new_with(|ptr| f(&T::uuidof(), ptr as _))
    }

    /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter.
    pub unsafe fn new_with<F>(f: F) -> HResult<Self>
        where F: FnOnce(*mut *mut T) -> HRESULT
    {
        let mut ptr = ptr::null_mut();
        let status = f(&mut ptr);
        if SUCCEEDED(status) {
            Ok(ComPtr::from_raw(ptr))
        } else {
            if !ptr.is_null() {
                let ptr = ptr as *mut IUnknown;
                (*ptr).Release();
            }
            Err(HResultError(status))
        }
    }

    pub fn as_raw(&self) -> *mut T {
        self.0
    }

    fn as_unknown(&self) -> &IUnknown {
        unsafe {
            &*(self.0 as *mut IUnknown)
        }
    }

    /// Performs QueryInterface fun.
    pub fn cast<U>(&self) -> HResult<ComPtr<U>> where U: Interface {
        unsafe {
            let mut obj = ptr::null_mut();
            self.as_unknown().QueryInterface(&U::uuidof(), &mut obj).to_result()?;
            Ok(ComPtr::from_raw(obj as *mut U))
        }
    }
}

impl<T> ops::Deref for ComPtr<T> where T: Interface {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> ops::DerefMut for ComPtr<T> where T: Interface {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.0 }
    }
}

impl<T> Clone for ComPtr<T> where T: Interface {
    fn clone(&self) -> Self {
        unsafe {
            self.as_unknown().AddRef();
            ComPtr(self.0)
        }
    }
}

impl<T> Drop for ComPtr<T> where T: Interface {
    fn drop(&mut self) {
        unsafe {
            self.as_unknown().Release();
        }
    }
}
<commit_msg>Remove unused and unsound DerefMut<commit_after>//! Similar to https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs , but can be null

use std::fmt;
use std::ops;
use std::ptr;
use winapi::Interface;
use winapi::ctypes::c_void;
use winapi::shared::guiddef::GUID;
use winapi::shared::winerror::HRESULT;
use winapi::shared::winerror::SUCCEEDED;
use winapi::um::unknwnbase::IUnknown;

pub type HResult<T> = Result<T, HResultError>;

/// An error code returned by a Windows API.
pub struct HResultError(HRESULT);

impl fmt::Debug for HResultError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:08X}", self.0 as u32)
    }
}

impl From<HRESULT> for HResultError {
    fn from(h: HRESULT) -> Self {
        HResultError(h)
    }
}

pub trait ToResult: Sized {
    fn to_result(self) -> HResult<()>;
}

impl ToResult for HRESULT {
    fn to_result(self) -> HResult<()> {
        if SUCCEEDED(self) {
            Ok(())
        } else {
            Err(HResultError(self))
        }
    }
}

pub fn as_ptr<T>(x: &T) -> *mut T {
    x as *const T as _
}

/// Forked from https://github.com/retep998/wio-rs/blob/44093f7db8/src/com.rs
#[derive(PartialEq, Debug)]
pub struct ComPtr<T>(*mut T) where T: Interface;

impl<T> ComPtr<T> where T: Interface {
    /// Creates a `ComPtr` to wrap a raw pointer.
    /// It takes ownership over the pointer which means it does __not__ call `AddRef`.
    /// `T` __must__ be a COM interface that inherits from `IUnknown`.
    pub unsafe fn from_raw(ptr: *mut T) -> ComPtr<T> {
        assert!(!ptr.is_null());
        ComPtr(ptr)
    }

    /// For use with APIs that take an interface UUID and
    /// "return" a new COM object through a `*mut *mut c_void` out-parameter.
    pub unsafe fn new_with_uuid<F>(f: F) -> HResult<Self>
        where F: FnOnce(&GUID, *mut *mut c_void) -> HRESULT
    {
        Self::new_with(|ptr| f(&T::uuidof(), ptr as _))
    }

    /// For use with APIs that "return" a new COM object through a `*mut *mut T` out-parameter.
    pub unsafe fn new_with<F>(f: F) -> HResult<Self>
        where F: FnOnce(*mut *mut T) -> HRESULT
    {
        let mut ptr = ptr::null_mut();
        let status = f(&mut ptr);
        if SUCCEEDED(status) {
            Ok(ComPtr::from_raw(ptr))
        } else {
            if !ptr.is_null() {
                let ptr = ptr as *mut IUnknown;
                (*ptr).Release();
            }
            Err(HResultError(status))
        }
    }

    pub fn as_raw(&self) -> *mut T {
        self.0
    }

    fn as_unknown(&self) -> &IUnknown {
        unsafe {
            &*(self.0 as *mut IUnknown)
        }
    }

    /// Performs QueryInterface fun.
    pub fn cast<U>(&self) -> HResult<ComPtr<U>> where U: Interface {
        unsafe {
            let mut obj = ptr::null_mut();
            self.as_unknown().QueryInterface(&U::uuidof(), &mut obj).to_result()?;
            Ok(ComPtr::from_raw(obj as *mut U))
        }
    }
}

impl<T> ops::Deref for ComPtr<T> where T: Interface {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { &*self.0 }
    }
}

impl<T> Clone for ComPtr<T> where T: Interface {
    fn clone(&self) -> Self {
        unsafe {
            self.as_unknown().AddRef();
            ComPtr(self.0)
        }
    }
}

impl<T> Drop for ComPtr<T> where T: Interface {
    fn drop(&mut self) {
        unsafe {
            self.as_unknown().Release();
        }
    }
}
<|endoftext|>


<commit_before>/*!
This is an OAuth 2.0 library for the Rust language.  It defines types and traits useful
for implementing an OAuth 2.0 compliant system as specified by RFC 6749.

WARNING: We've just started.  It is practically useless at this point.

Applicability

OAuth 2.0 is a protocol framework that allows an application (the Client, usually a web
site) to obtain limited access to an HTTP service (the Resource Server) on behalf of
a Resource Owner which interacts with the Client via a User-Agent (browser).
This is mediated via an Authorization Server (which could be the Resource Server
itself, or separated from it).

The term "client" can be confusing here.  The client of the OAuth service is typically a
web site.   The client of that web site is the user-agent (browser).  To minimize
confusion, the user-agent will not be referred to as a client.

OAuth is a Framework Only

OAuth 2.0 is an Authorization Framework.  In order to get something usable, you must supply
the missing pieces.  And there are quite a few missing pieces which you will need to implement
in order to get a working system.  These include:

Initial client registration (between the Client and the Authorization
    Server).  Often people just use config files, but this is for you to decide.

Storing state.  Often database tables are used.  Manytimes the Authorization
    Server and Resource Server use the same database, or perhaps are the same
    server.  This is out of scope, and left up to you.

User-Agent authentication and authorization (by the Authorization Server), where you
    should not only authenticate the resource owner, but also ask them if they really want
    to allow the client to have the rights to act on their behalf under the Scope
    requested.

Sample Implementation

Please see `tests/lib.rs` for a sample implementation.

Coverage and Standard Support

We do not (and likely will not) support every standard compliant way to use OAuth 2.0.
But we will try to be as flexible as possible, and extend this library as time and resources
allow.  That being said, the following limitations currently apply:

We only explicitly support the "authorization code" grant type, which is the most common
    and most secure.  "Implicit", "resource owner password credentials", and "client
    credentials" grant types are not supported.

The authorization server acts on behalf of the resource server, so virtually we are not
    supporting independent resource servers.

We do not enforce that traffic be protected via TLS, although the standard requires that
    most (and suggests all) traffic be so protected.  This is left up to the user.

All IDs and tokens are taken to be respresented in UTF-8 encodings.  We will not
    work with other encodings.  The standard is silent on most encoding issues.

Refresh tokens are not yet supported

I'm not sure that the HTTP Status Codes returned to the user-agent on various failures
    are appropriate.

FIXME: More limitations will be added to this list as the development progresses.

*/

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate url;
#[macro_use] extern crate hyper;
extern crate textnonce;
extern crate serde_json;

pub mod syntax;
pub mod authz_server;
pub mod client;
pub mod client_type;
pub mod client_data;
pub mod error;

pub use authz_server::{AuthzServer, AuthzErrorCode, AuthzError, TokenErrorCode,
                       TokenError, AuthzRequestData, TokenData};
pub use client::Client;
pub use client_type::ClientType;
pub use client_data::ClientData;
pub use error::OauthError;
<commit_msg>Fix doc comment to remove warning no longer applicable<commit_after>/*!
This is an OAuth 2.0 library for the Rust language.  It defines types and traits useful
for implementing an OAuth 2.0 compliant system as specified by RFC 6749.

The current implementation allows you to build the most common and most secure
type of OAuth 2.0 infrastructure, but is not complete, and may not be
absolutely correct.  Please file bug reports or pull requests if you notice
any deviation from RFC 6749, or if you have any other issues.

Applicability

OAuth 2.0 is a protocol framework that allows an application (the Client, usually a web
site) to obtain limited access to an HTTP service (the Resource Server) on behalf of
a Resource Owner which interacts with the Client via a User-Agent (browser).
This is mediated via an Authorization Server (which could be the Resource Server
itself, or separated from it).

The term "client" can be confusing here.  The client of the OAuth service is typically a
web site.   The client of that web site is the user-agent (browser).  To minimize
confusion, the user-agent will not be referred to as a client.

OAuth is a Framework Only

OAuth 2.0 is an Authorization Framework.  In order to get something usable, you must supply
the missing pieces.  And there are quite a few missing pieces which you will need to implement
in order to get a working system.  These include:

Initial client registration (between the Client and the Authorization
    Server).  Often people just use config files, but this is for you to decide.

Storing state.  Often database tables are used.  Manytimes the Authorization
    Server and Resource Server use the same database, or perhaps are the same
    server.  This is out of scope, and left up to you.

User-Agent authentication and authorization (by the Authorization Server), where you
    should not only authenticate the resource owner, but also ask them if they really want
    to allow the client to have the rights to act on their behalf under the Scope
    requested.

Sample Implementation

Please see `tests/lib.rs` for a sample implementation.

Coverage and Standard Support

We do not (and likely will not) support every standard compliant way to use OAuth 2.0.
But we will try to be as flexible as possible, and extend this library as time and resources
allow.  That being said, the following limitations currently apply:

We only explicitly support the "authorization code" grant type, which is the most common
    and most secure.  "Implicit", "resource owner password credentials", and "client
    credentials" grant types are not supported.

The authorization server acts on behalf of the resource server, so virtually we are not
    supporting independent resource servers.

We do not enforce that traffic be protected via TLS, although the standard requires that
    most (and suggests all) traffic be so protected.  This is left up to the user.

All IDs and tokens are taken to be respresented in UTF-8 encodings.  We will not
    work with other encodings.  The standard is silent on most encoding issues.

Refresh tokens are not yet supported

I'm not sure that the HTTP Status Codes returned to the user-agent on various failures
    are appropriate.

FIXME: More limitations will be added to this list as the development progresses.

*/

#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate url;
#[macro_use] extern crate hyper;
extern crate textnonce;
extern crate serde_json;

pub mod syntax;
pub mod authz_server;
pub mod client;
pub mod client_type;
pub mod client_data;
pub mod error;

pub use authz_server::{AuthzServer, AuthzErrorCode, AuthzError, TokenErrorCode,
                       TokenError, AuthzRequestData, TokenData};
pub use client::Client;
pub use client_type::ClientType;
pub use client_data::ClientData;
pub use error::OauthError;
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! Interpolation algorithms.
//!
//! Interpolation is used in animation,
//! to describe smooth shapes and to make transitions.
//! Any object that fullfill certain mathematical
//! properties can be interpolated.
//! A common technique is using one ore more 'numbers'
//! controlling the mixture of states.
//! The choice of interpolation algorithm depends often
//! on the circumstances where it used.

/// Performs linear interpolation.
/// A linear interpolation consists of two states 'a' and 'b'.
/// The 't' variable is a factor between 0 and 1 that
/// gives weight to 'a' or 'b'.
/// When 't' is zero then 'a' has full weight.
/// When 't' is one then 'b' has full weight.
#[inline(always)]
pub fn lerp<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    a: T,
    b: T,
    t: U
) -> T {
    a + (b - a) * t
}

/// Performs linear interpolation on array of size 3.
#[inline(always)]
pub fn lerp_2<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    a: [T, ..2],
    b: [T, ..2],
    t: U
) -> [T, ..2] {
    [lerp(a[0], b[0], t),
    lerp(a[1], b[1], t)]
}

/// Performs linear interpolation on array of size 3.
#[inline(always)]
pub fn lerp_3<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    a: [T, ..3],
    b: [T, ..3],
    t: U
) -> [T, ..3] {
    [lerp(a[0], b[0], t),
    lerp(a[1], b[1], t),
    lerp(a[2], b[2], t)]
}

/// Performs linear interpolation on array of size 4.
#[inline(always)]
pub fn lerp_4<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    a: [T, ..4],
    b: [T, ..4],
    t: U
) -> [T, ..4] {
    [lerp(a[0], b[0], t),
    lerp(a[1], b[1], t),
    lerp(a[2], b[2], t),
    lerp(a[3], b[3], t)]
}

/// Performs linear interpolation on array of size 5.
#[inline(always)]
pub fn lerp_5<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    a: [T, ..5],
    b: [T, ..5],
    t: U
) -> [T, ..5] {
    [lerp(a[0], b[0], t),
    lerp(a[1], b[1], t),
    lerp(a[2], b[2], t),
    lerp(a[3], b[3], t),
    lerp(a[4], b[4], t)]
}

/// Performs quadratic beziér interpolation.
/// This is done by nesting linear interpolations.
/// For more information, see:
///
/// Beziér Curve at Wikipedia
#[inline(always)]
pub fn quad_bez<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    x0: T,
    x1: T,
    x2: T,
    t: U
) -> T {
    let x_0_1 = lerp(x0, x1, t);
    let x_1_2 = lerp(x1, x2, t);
    lerp(x_0_1, x_1_2, t)
}

/// Performs cubic beziér interpolation.
/// This is done by interpolation between two quadratic beziér.
/// For more information, see:
///
/// Beziér Curve at Wikipedia
#[inline(always)]
pub fn cub_bez<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    x0: T,
    x1: T,
    x2: T,
    x3: T,
    t: U
) -> T {
    let x_0_2 = quad_bez(x0, x1, x2, t);
    let x_1_3 = quad_bez(x1, x2, x3, t);
    lerp(x_0_2, x_1_3, t)
}

<commit_msg>Removed `lerp_x` functions<commit_after>#![deny(missing_docs)]

//! Interpolation algorithms.
//!
//! Interpolation is used in animation,
//! to describe smooth shapes and to make transitions.
//! Any object that fullfill certain mathematical
//! properties can be interpolated.
//! A common technique is using one ore more 'numbers'
//! controlling the mixture of states.
//! The choice of interpolation algorithm depends often
//! on the circumstances where it used.

/// Performs linear interpolation.
/// A linear interpolation consists of two states 'a' and 'b'.
/// The 't' variable is a factor between 0 and 1 that
/// gives weight to 'a' or 'b'.
/// When 't' is zero then 'a' has full weight.
/// When 't' is one then 'b' has full weight.
#[inline(always)]
pub fn lerp<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    a: T,
    b: T,
    t: U
) -> T {
    a + (b - a) * t
}

/// Performs quadratic beziér interpolation.
/// This is done by nesting linear interpolations.
/// For more information, see:
///
/// Beziér Curve at Wikipedia
#[inline(always)]
pub fn quad_bez<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    x0: T,
    x1: T,
    x2: T,
    t: U
) -> T {
    let x_0_1 = lerp(x0, x1, t);
    let x_1_2 = lerp(x1, x2, t);
    lerp(x_0_1, x_1_2, t)
}

/// Performs cubic beziér interpolation.
/// This is done by interpolation between two quadratic beziér.
/// For more information, see:
///
/// Beziér Curve at Wikipedia
#[inline(always)]
pub fn cub_bez<T: Copy + Add<T, T> + Sub<T, T> + Mul, U: Copy>(
    x0: T,
    x1: T,
    x2: T,
    x3: T,
    t: U
) -> T {
    let x_0_2 = quad_bez(x0, x1, x2, t);
    let x_1_3 = quad_bez(x1, x2, x3, t);
    lerp(x_0_2, x_1_3, t)
}

<|endoftext|>


<commit_before>use render::Renderer;
use result;
use hyper;
use hyper::client;

pub struct InfluxDbRenderer {
    write_url: String,
    tags: Option<String>,
}

impl InfluxDbRenderer {
    pub fn new(write_url: &str, tags: Option<String>) -> InfluxDbRenderer {
        InfluxDbRenderer {
            write_url: String::from(write_url),
            tags: tags,
        }
    }
}

impl Renderer for InfluxDbRenderer {
    fn render(&mut self, result: result::RequestLogAnalyzerResult) -> () {
        let client = client::Client::new();
        let data = self.post_body(result);
        let response = client.post(&self.write_url)
            .body(&data)
            .send()
            .expect("Could not connect to InfluxDB host.");

        if response.status.class() != hyper::status::StatusClass::Success {
            panic!("POSTing data to InfluxDB failed: {:?}", response.status);
        }
    }
}

impl InfluxDbRenderer {
    fn post_body(&self, result: result::RequestLogAnalyzerResult) -> String {
        let mut timing_values = String::from("");
        let mut error_rate_values = String::from("");

        let tags: String = match self.tags {
            Some(ref tags) => format!(",{}", tags),
            None => String::from(""),
        };

        match result.timing {
            Some(timing) => {
                timing_values = format!(",\
    				time_max={},time_min={},time_avg={},time_median={},\
                                         time_90percent={}",
                                        timing.max,
                                        timing.min,
                                        timing.avg,
                                        timing.median,
                                        timing.percentile90);
            }
            None => warn!("No matching log lines in file."),
        }

        match result.error {
            Some(error) => {
                error_rate_values = format!(",\
    				client_error_4xx_rate={},server_error_5xx_rate={}",
                                            error.client_error_4xx,
                                            error.server_error_5xx);
            }
            None => warn!("No matching log lines in file."),
        }

        format!("request_log{} count={}{}{}",
                tags,
                result.count,
                timing_values,
                error_rate_values)
    }
}

#[cfg(test)]
mod tests {
    use std::str;
    use analyzer;
    use super::*;

    fn get_result_fixture() -> result::RequestLogAnalyzerResult {
        result::RequestLogAnalyzerResult {
            count: 3,
            timing: Some(analyzer::TimingResult {
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
                count: 3,
            }),
            error: Some(analyzer::aggregated_error_rates::ErrorRatesResult {
                client_error_4xx: 0.1,
                server_error_5xx: 0.2,
            }),
        }
    }

    #[test]
    fn test_instantiate() {
        InfluxDbRenderer::new("http://example.com/write?db=testdb", None);
    }

    #[test]
    fn test_post_body() {
        let renderer = InfluxDbRenderer::new("http://example.com/write?db=testdb", None);
        let result = renderer.post_body(get_result_fixture());

        assert!(result.starts_with("request_log "));
        assert_eq!(result.matches(" ").count(), 1);

        assert!(result.contains("count=3"));
        assert!(result.contains("time_max=100"));
        assert!(result.contains("time_min=1"));
        assert!(result.contains("time_avg=37"));
        assert!(result.contains("time_median=10"));
        assert!(result.contains("time_90percent=100"));
        assert!(result.contains("client_error_4xx_rate=0.1"));
        assert!(result.contains("server_error_5xx_rate=0.2"));
    }

    #[test]
    fn test_post_body_with_tag() {
        let tags = String::from("host=testhost");
        let renderer = InfluxDbRenderer::new("http://example.com/write?db=testdb", Some(tags));
        let result = renderer.post_body(get_result_fixture());

        assert!(result.starts_with("request_log,host=testhost "));
        assert_eq!(result.matches(" ").count(), 1);

        assert!(result.contains("count=3"));
    }

    #[test]
    fn test_post_body_empty() {
        let renderer = InfluxDbRenderer::new("http://example.com/write?db=testdb", None);

        let result = renderer.post_body(result::RequestLogAnalyzerResult {
            count: 0,
            timing: None,
            error: None,
        });

        assert!(result.starts_with("request_log "));

        assert!(result.ends_with("count=0"));

        // Don't include empty fields
        assert!(!result.contains("time_max="));
        assert!(!result.contains("time_min="));
        assert!(!result.contains("time_avg="));
        assert!(!result.contains("time_median="));
        assert!(!result.contains("time_90percent="));
        assert!(!result.contains("client_error_4xx_rate="));
        assert!(!result.contains("server_error_5xx_rate="));
    }
}
<commit_msg>Remove unused import<commit_after>use render::Renderer;
use result;
use hyper;
use hyper::client;

pub struct InfluxDbRenderer {
    write_url: String,
    tags: Option<String>,
}

impl InfluxDbRenderer {
    pub fn new(write_url: &str, tags: Option<String>) -> InfluxDbRenderer {
        InfluxDbRenderer {
            write_url: String::from(write_url),
            tags: tags,
        }
    }
}

impl Renderer for InfluxDbRenderer {
    fn render(&mut self, result: result::RequestLogAnalyzerResult) -> () {
        let client = client::Client::new();
        let data = self.post_body(result);
        let response = client.post(&self.write_url)
            .body(&data)
            .send()
            .expect("Could not connect to InfluxDB host.");

        if response.status.class() != hyper::status::StatusClass::Success {
            panic!("POSTing data to InfluxDB failed: {:?}", response.status);
        }
    }
}

impl InfluxDbRenderer {
    fn post_body(&self, result: result::RequestLogAnalyzerResult) -> String {
        let mut timing_values = String::from("");
        let mut error_rate_values = String::from("");

        let tags: String = match self.tags {
            Some(ref tags) => format!(",{}", tags),
            None => String::from(""),
        };

        match result.timing {
            Some(timing) => {
                timing_values = format!(",\
    				time_max={},time_min={},time_avg={},time_median={},\
                                         time_90percent={}",
                                        timing.max,
                                        timing.min,
                                        timing.avg,
                                        timing.median,
                                        timing.percentile90);
            }
            None => warn!("No matching log lines in file."),
        }

        match result.error {
            Some(error) => {
                error_rate_values = format!(",\
    				client_error_4xx_rate={},server_error_5xx_rate={}",
                                            error.client_error_4xx,
                                            error.server_error_5xx);
            }
            None => warn!("No matching log lines in file."),
        }

        format!("request_log{} count={}{}{}",
                tags,
                result.count,
                timing_values,
                error_rate_values)
    }
}

#[cfg(test)]
mod tests {
    use analyzer;
    use super::*;

    fn get_result_fixture() -> result::RequestLogAnalyzerResult {
        result::RequestLogAnalyzerResult {
            count: 3,
            timing: Some(analyzer::TimingResult {
                max: 100,
                min: 1,
                avg: 37,
                median: 10,
                percentile90: 100,
                count: 3,
            }),
            error: Some(analyzer::aggregated_error_rates::ErrorRatesResult {
                client_error_4xx: 0.1,
                server_error_5xx: 0.2,
            }),
        }
    }

    #[test]
    fn test_instantiate() {
        InfluxDbRenderer::new("http://example.com/write?db=testdb", None);
    }

    #[test]
    fn test_post_body() {
        let renderer = InfluxDbRenderer::new("http://example.com/write?db=testdb", None);
        let result = renderer.post_body(get_result_fixture());

        assert!(result.starts_with("request_log "));
        assert_eq!(result.matches(" ").count(), 1);

        assert!(result.contains("count=3"));
        assert!(result.contains("time_max=100"));
        assert!(result.contains("time_min=1"));
        assert!(result.contains("time_avg=37"));
        assert!(result.contains("time_median=10"));
        assert!(result.contains("time_90percent=100"));
        assert!(result.contains("client_error_4xx_rate=0.1"));
        assert!(result.contains("server_error_5xx_rate=0.2"));
    }

    #[test]
    fn test_post_body_with_tag() {
        let tags = String::from("host=testhost");
        let renderer = InfluxDbRenderer::new("http://example.com/write?db=testdb", Some(tags));
        let result = renderer.post_body(get_result_fixture());

        assert!(result.starts_with("request_log,host=testhost "));
        assert_eq!(result.matches(" ").count(), 1);

        assert!(result.contains("count=3"));
    }

    #[test]
    fn test_post_body_empty() {
        let renderer = InfluxDbRenderer::new("http://example.com/write?db=testdb", None);

        let result = renderer.post_body(result::RequestLogAnalyzerResult {
            count: 0,
            timing: None,
            error: None,
        });

        assert!(result.starts_with("request_log "));

        assert!(result.ends_with("count=0"));

        // Don't include empty fields
        assert!(!result.contains("time_max="));
        assert!(!result.contains("time_min="));
        assert!(!result.contains("time_avg="));
        assert!(!result.contains("time_median="));
        assert!(!result.contains("time_90percent="));
        assert!(!result.contains("client_error_4xx_rate="));
        assert!(!result.contains("server_error_5xx_rate="));
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 oauth-client-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! OAuth 1.0 client library for Rust.
//!
//! Dependent on libcurl.
//!
//! [Repository](https://github.com/charlag/oauth-client-rs)
//!
//! # Examples
//!
//! Send request for request token.
//!
//! ```
//! const REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
//! let consumer = oauth_client::Token::new("key", "secret");
//! let bytes = oauth_client::get(REQUEST_TOKEN, &consumer, None, None).unwrap();
//! ```

#![warn(bad_style)]
#![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate crypto;
extern crate curl;
#[macro_use]
extern crate log;
extern crate rand;
extern crate rustc_serialize;
extern crate time;
extern crate url;

use std::borrow::Cow;
use std::collections::HashMap;
use std::io::Read;
use std::{error, fmt};
use rand::Rng;
use rustc_serialize::base64::{self, ToBase64};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha1::Sha1;
use curl::easy::{Easy, List};
use url::percent_encoding;

/// The `Error` type
#[derive(Debug)]
pub enum Error {
    /// Curl error
    Curl(curl::Error),
    /// Http status
    HttpStatus(u32),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Curl(ref err) => write!(f, "Curl error: {}", err),
            Error::HttpStatus(ref resp) => write!(f, "HTTP status error: {}", resp),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Curl(ref err) => err.description(),
            Error::HttpStatus(_) => "HTTP status error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Curl(ref err) => Some(err),
            Error::HttpStatus(_) => None,
        }
    }
}

impl From<curl::Error> for Error {
    fn from(err: curl::Error) -> Error {
        Error::Curl(err)
    }
}

/// Token structure for the OAuth
#[derive(Clone, Debug)]
pub struct Token<'a> {
    /// 'key' field of the token
    pub key: Cow<'a, str>,
    /// 'secret' part of the token
    pub secret: Cow<'a, str>,
}

impl<'a> Token<'a> {
    /// Create new token from `key` and `secret`
    ///
    /// # Examples
    ///
    /// ```
    /// let consumer = oauth_client::Token::new("key", "secret");
    /// ```
    pub fn new<K, S>(key: K, secret: S) -> Token<'a>
        where K: Into<Cow<'a, str>>,
              S: Into<Cow<'a, str>>
    {
        Token {
            key: key.into(),
            secret: secret.into(),
        }
    }
}

/// Alias for `HashMap<Cow<'a, str>, Cow<'a, str>>`
pub type ParamList<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;

fn insert_param<'a, K, V>(param: &mut ParamList<'a>, key: K, value: V) -> Option<Cow<'a, str>>
    where K: Into<Cow<'a, str>>,
          V: Into<Cow<'a, str>>
{
    param.insert(key.into(), value.into())
}

fn join_query<'a>(param: &ParamList<'a>) -> String {
    let mut pairs = param.iter()
                         .map(|(k, v)| format!("{}={}", encode(&k), encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    pairs.join("&")
}

/// Percent encode string
fn encode(s: &str) -> String {
    percent_encoding::utf8_percent_encode(s, percent_encoding::SIMPLE_ENCODE_SET)
        .collect::<String>()
}

/// Wrapper function around 'crypto::Hmac'
fn hmac_sha1(key: &[u8], data: &[u8]) -> MacResult {
    let mut hmac = Hmac::new(Sha1::new(), key);
    hmac.input(data);
    hmac.result()
}

/// Create signature. See https://dev.twitter.com/oauth/overview/creating-signatures
fn signature(method: &str,
             uri: &str,
             query: &str,
             consumer_secret: &str,
             token_secret: Option<&str>)
             -> String {
    let base = format!("{}&{}&{}", encode(method), encode(uri), encode(query));
    let key = format!("{}&{}",
                      encode(consumer_secret),
                      encode(token_secret.unwrap_or("")));
    let conf = base64::Config {
        char_set: base64::CharacterSet::Standard,
        newline: base64::Newline::LF,
        pad: true,
        line_length: None,
    };
    debug!("Signature base string: {}", base);
    debug!("Authorization header: Authorization: {}", base);
    hmac_sha1(key.as_bytes(), base.as_bytes()).code().to_base64(conf)
}

/// Constuct plain-text header
fn header(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}=\"{}\"", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("OAuth {}", pairs.join(", "))
}

/// Construct plain-text body from 'PaaramList'
fn body(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| !k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}={}", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("{}", pairs.join("&"))
}

/// Create header and body
fn get_header(method: &str,
              uri: &str,
              consumer: &Token,
              token: Option<&Token>,
              other_param: Option<&ParamList>)
              -> (String, String) {
    let mut param = HashMap::new();
    let timestamp = format!("{}", time::now_utc().to_timespec().sec);
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();

    let _ = insert_param(&mut param, "oauth_consumer_key", consumer.key.to_string());
    let _ = insert_param(&mut param, "oauth_nonce", nonce);
    let _ = insert_param(&mut param, "oauth_signature_method", "HMAC-SHA1");
    let _ = insert_param(&mut param, "oauth_timestamp", timestamp);
    let _ = insert_param(&mut param, "oauth_version", "1.0");
    if let Some(tk) = token {
        let _ = insert_param(&mut param, "oauth_token", tk.key.as_ref());
    }

    if let Some(ps) = other_param {
        for (k, v) in ps.iter() {
            let _ = insert_param(&mut param, k.as_ref(), v.as_ref());
        }
    }

    let sign = signature(method,
                         uri,
                         join_query(&param).as_ref(),
                         consumer.secret.as_ref(),
                         token.map(|t| t.secret.as_ref()));
    let _ = insert_param(&mut param, "oauth_signature", sign);

    (header(&param), body(&param))
}

/// Create an authorization header.
/// See https://dev.twitter.com/oauth/overview/authorizing-requests
///
/// # Examples
///
/// ```
/// # extern crate curl;
/// # extern crate oauth_client;
/// # fn main() {
/// const REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
/// let consumer = oauth_client::Token::new("key", "secret");
/// let header = oauth_client::authorization_header("GET", REQUEST_TOKEN, &consumer, None, None);
/// # }
/// ```
pub fn authorization_header(method: &str,
                            uri: &str,
                            consumer: &Token,
                            token: Option<&Token>,
                            other_param: Option<&ParamList>)
                            -> String {
    get_header(method, uri, consumer, token, other_param).0
}

/// Send authorized GET request to the specified URL.
/// `consumer` is a consumer token.
///
/// # Examples
///
/// ```
/// let REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
/// let consumer = oauth_client::Token::new("key", "secret");
/// let bytes = oauth_client::get(REQUEST_TOKEN, &consumer, None, None).unwrap();
/// let resp = String::from_utf8(bytes).unwrap();
/// ```
pub fn get(uri: &str,
           consumer: &Token,
           token: Option<&Token>,
           other_param: Option<&ParamList>)
           -> Result<Vec<u8>, Error> {
    let (header, body) = get_header("GET", uri, consumer, token, other_param);
    let req_uri = if body.len() > 0 {
        format!("{}?{}", uri, body)
    } else {
        format!("{}", uri)
    };
    let mut handle = Easy::new();
    let mut list = List::new();
    list.append(format!("Authorization: {}", header).as_ref()).unwrap();
    let mut resp = Vec::new();
    try!(handle.url(req_uri.as_ref()));
    try!(handle.http_headers(list));
    try!(handle.get(true));
    {
        let mut transfer = handle.transfer();
        try!(transfer.write_function(|data| {
            resp.extend_from_slice(data);
            Ok(data.len())
        }));
        try!(transfer.perform());
    }
    let code = try!(handle.response_code());
    if code != 200 {
        return Err(Error::HttpStatus(code))
    }
    Ok(resp)
}

/// Send authorized POST request to the specified URL.
/// `consumer` is a consumer token.
///
/// # Examples
///
/// ```
/// # let request = oauth_client::Token::new("key", "secret");
/// let ACCESS_TOKEN: &'static str = "http://oauthbin.com/v1/access-token";
/// let consumer = oauth_client::Token::new("key", "secret");
/// let bytes = oauth_client::post(ACCESS_TOKEN, &consumer, Some(&request), None).unwrap();
/// let resp = String::from_utf8(bytes).unwrap();
/// ```
pub fn post(uri: &str,
            consumer: &Token,
            token: Option<&Token>,
            other_param: Option<&ParamList>)
            -> Result<Vec<u8>, Error> {
    let (header, body) = get_header("POST", uri, consumer, token, other_param);
    let mut handle = Easy::new();
    let mut list = List::new();
    list.append(format!("Authorization: {}", header).as_ref()).unwrap();
    let mut resp = Vec::new();
    try!(handle.url(uri.as_ref()));
    try!(handle.http_headers(list));
    try!(handle.post(true));
    try!(handle.post_field_size(body.len() as u64));
    {
        let mut transfer = handle.transfer();
        try!(transfer.read_function(|into| {
            let mut body = body.as_bytes();
            Ok(body.read(into).unwrap())
        }));
        try!(transfer.write_function(|data| {
            resp.extend_from_slice(data);
            Ok(data.len())
        }));
        try!(transfer.perform());
    }
    let code = try!(handle.response_code());
    if code != 200 {
        return Err(Error::HttpStatus(code))
    }
    Ok(resp)
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use super::encode;

    #[test]
    fn query() {
        let mut map = HashMap::new();
        let _ = map.insert("aaa".into(), "AAA".into());
        let _ = map.insert("bbbb".into(), "BBBB".into());
        let query = super::join_query(&map);
        assert_eq!("aaa=AAA&bbbb=BBBB", query);
    }

    #[test]
    fn test_encode() {
        let method = "GET";
        let uri = "http://oauthbin.com/v1/request-token";
        let encoded_uri = "http%3A%2F%2Foauthbin.com%2Fv1%2Frequest-token";
        let query = "oauth_consumer_key=key&oauth_nonce=s6HGl3GhmsDsmpgeLo6lGtKs7rQEzzsA&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1471445561&oauth_version=1.\
                     0";
        let encoded_query = "oauth_consumer_key%3Dkey%26oauth_nonce%3Ds6HGl3GhmsDsmpgeLo6lGtKs7rQEzzsA%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1471445561%26oauth_version%3D1.\
                             0";

        assert_eq!(encode(method), "GET");
        assert_eq!(encode(uri), encoded_uri);
        assert_eq!(encode(query), encoded_query);
    }
}
<commit_msg>update encode fn<commit_after>// Copyright 2016 oauth-client-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! OAuth 1.0 client library for Rust.
//!
//! Dependent on libcurl.
//!
//! [Repository](https://github.com/charlag/oauth-client-rs)
//!
//! # Examples
//!
//! Send request for request token.
//!
//! ```
//! const REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
//! let consumer = oauth_client::Token::new("key", "secret");
//! let bytes = oauth_client::get(REQUEST_TOKEN, &consumer, None, None).unwrap();
//! ```

#![warn(bad_style)]
#![warn(missing_docs)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate crypto;
extern crate curl;
#[macro_use]
extern crate log;
extern crate rand;
extern crate rustc_serialize;
extern crate time;
extern crate url;

use std::borrow::Cow;
use std::collections::HashMap;
use std::io::Read;
use std::{error, fmt};
use rand::Rng;
use rustc_serialize::base64::{self, ToBase64};
use crypto::hmac::Hmac;
use crypto::mac::{Mac, MacResult};
use crypto::sha1::Sha1;
use curl::easy::{Easy, List};
use url::{form_urlencoded, percent_encoding};

/// The `Error` type
#[derive(Debug)]
pub enum Error {
    /// Curl error
    Curl(curl::Error),
    /// Http status
    HttpStatus(u32),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Curl(ref err) => write!(f, "Curl error: {}", err),
            Error::HttpStatus(ref resp) => write!(f, "HTTP status error: {}", resp),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Curl(ref err) => err.description(),
            Error::HttpStatus(_) => "HTTP status error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Curl(ref err) => Some(err),
            Error::HttpStatus(_) => None,
        }
    }
}

impl From<curl::Error> for Error {
    fn from(err: curl::Error) -> Error {
        Error::Curl(err)
    }
}

/// Token structure for the OAuth
#[derive(Clone, Debug)]
pub struct Token<'a> {
    /// 'key' field of the token
    pub key: Cow<'a, str>,
    /// 'secret' part of the token
    pub secret: Cow<'a, str>,
}

impl<'a> Token<'a> {
    /// Create new token from `key` and `secret`
    ///
    /// # Examples
    ///
    /// ```
    /// let consumer = oauth_client::Token::new("key", "secret");
    /// ```
    pub fn new<K, S>(key: K, secret: S) -> Token<'a>
        where K: Into<Cow<'a, str>>,
              S: Into<Cow<'a, str>>
    {
        Token {
            key: key.into(),
            secret: secret.into(),
        }
    }
}

/// Alias for `HashMap<Cow<'a, str>, Cow<'a, str>>`
pub type ParamList<'a> = HashMap<Cow<'a, str>, Cow<'a, str>>;

fn insert_param<'a, K, V>(param: &mut ParamList<'a>, key: K, value: V) -> Option<Cow<'a, str>>
    where K: Into<Cow<'a, str>>,
          V: Into<Cow<'a, str>>
{
    param.insert(key.into(), value.into())
}

fn join_query<'a>(param: &ParamList<'a>) -> String {
    let mut pairs = param.iter()
                         .map(|(k, v)| format!("{}={}", encode(&k), encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    pairs.join("&")
}

/// Percent encode string
fn encode(s: &str) -> String {
    form_urlencoded::byte_serialize(s.as_bytes()).collect::<String>()
}

/// Wrapper function around 'crypto::Hmac'
fn hmac_sha1(key: &[u8], data: &[u8]) -> MacResult {
    let mut hmac = Hmac::new(Sha1::new(), key);
    hmac.input(data);
    hmac.result()
}

/// Create signature. See https://dev.twitter.com/oauth/overview/creating-signatures
fn signature(method: &str,
             uri: &str,
             query: &str,
             consumer_secret: &str,
             token_secret: Option<&str>)
             -> String {
    let base = format!("{}&{}&{}", encode(method), encode(uri), encode(query));
    let key = format!("{}&{}",
                      encode(consumer_secret),
                      encode(token_secret.unwrap_or("")));
    let conf = base64::Config {
        char_set: base64::CharacterSet::Standard,
        newline: base64::Newline::LF,
        pad: true,
        line_length: None,
    };
    debug!("Signature base string: {}", base);
    debug!("Authorization header: Authorization: {}", base);
    hmac_sha1(key.as_bytes(), base.as_bytes()).code().to_base64(conf)
}

/// Constuct plain-text header
fn header(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}=\"{}\"", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("OAuth {}", pairs.join(", "))
}

/// Construct plain-text body from 'PaaramList'
fn body(param: &ParamList) -> String {
    let mut pairs = param.iter()
                         .filter(|&(k, _)| !k.starts_with("oauth_"))
                         .map(|(k, v)| format!("{}={}", k, encode(&v)))
                         .collect::<Vec<_>>();
    pairs.sort();
    format!("{}", pairs.join("&"))
}

/// Create header and body
fn get_header(method: &str,
              uri: &str,
              consumer: &Token,
              token: Option<&Token>,
              other_param: Option<&ParamList>)
              -> (String, String) {
    let mut param = HashMap::new();
    let timestamp = format!("{}", time::now_utc().to_timespec().sec);
    let nonce = rand::thread_rng().gen_ascii_chars().take(32).collect::<String>();

    let _ = insert_param(&mut param, "oauth_consumer_key", consumer.key.to_string());
    let _ = insert_param(&mut param, "oauth_nonce", nonce);
    let _ = insert_param(&mut param, "oauth_signature_method", "HMAC-SHA1");
    let _ = insert_param(&mut param, "oauth_timestamp", timestamp);
    let _ = insert_param(&mut param, "oauth_version", "1.0");
    if let Some(tk) = token {
        let _ = insert_param(&mut param, "oauth_token", tk.key.as_ref());
    }

    if let Some(ps) = other_param {
        for (k, v) in ps.iter() {
            let _ = insert_param(&mut param, k.as_ref(), v.as_ref());
        }
    }

    let sign = signature(method,
                         uri,
                         join_query(&param).as_ref(),
                         consumer.secret.as_ref(),
                         token.map(|t| t.secret.as_ref()));
    let _ = insert_param(&mut param, "oauth_signature", sign);

    (header(&param), body(&param))
}

/// Create an authorization header.
/// See https://dev.twitter.com/oauth/overview/authorizing-requests
///
/// # Examples
///
/// ```
/// # extern crate curl;
/// # extern crate oauth_client;
/// # fn main() {
/// const REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
/// let consumer = oauth_client::Token::new("key", "secret");
/// let header = oauth_client::authorization_header("GET", REQUEST_TOKEN, &consumer, None, None);
/// # }
/// ```
pub fn authorization_header(method: &str,
                            uri: &str,
                            consumer: &Token,
                            token: Option<&Token>,
                            other_param: Option<&ParamList>)
                            -> String {
    get_header(method, uri, consumer, token, other_param).0
}

/// Send authorized GET request to the specified URL.
/// `consumer` is a consumer token.
///
/// # Examples
///
/// ```
/// let REQUEST_TOKEN: &'static str = "http://oauthbin.com/v1/request-token";
/// let consumer = oauth_client::Token::new("key", "secret");
/// let bytes = oauth_client::get(REQUEST_TOKEN, &consumer, None, None).unwrap();
/// let resp = String::from_utf8(bytes).unwrap();
/// ```
pub fn get(uri: &str,
           consumer: &Token,
           token: Option<&Token>,
           other_param: Option<&ParamList>)
           -> Result<Vec<u8>, Error> {
    let (header, body) = get_header("GET", uri, consumer, token, other_param);
    let req_uri = if body.len() > 0 {
        format!("{}?{}", uri, body)
    } else {
        format!("{}", uri)
    };
    let mut handle = Easy::new();
    let mut list = List::new();
    list.append(format!("Authorization: {}", header).as_ref()).unwrap();
    let mut resp = Vec::new();
    try!(handle.url(req_uri.as_ref()));
    try!(handle.http_headers(list));
    try!(handle.get(true));
    {
        let mut transfer = handle.transfer();
        try!(transfer.write_function(|data| {
            resp.extend_from_slice(data);
            Ok(data.len())
        }));
        try!(transfer.perform());
    }
    let code = try!(handle.response_code());
    if code != 200 {
        return Err(Error::HttpStatus(code))
    }
    Ok(resp)
}

/// Send authorized POST request to the specified URL.
/// `consumer` is a consumer token.
///
/// # Examples
///
/// ```
/// # let request = oauth_client::Token::new("key", "secret");
/// let ACCESS_TOKEN: &'static str = "http://oauthbin.com/v1/access-token";
/// let consumer = oauth_client::Token::new("key", "secret");
/// let bytes = oauth_client::post(ACCESS_TOKEN, &consumer, Some(&request), None).unwrap();
/// let resp = String::from_utf8(bytes).unwrap();
/// ```
pub fn post(uri: &str,
            consumer: &Token,
            token: Option<&Token>,
            other_param: Option<&ParamList>)
            -> Result<Vec<u8>, Error> {
    let (header, body) = get_header("POST", uri, consumer, token, other_param);
    let mut handle = Easy::new();
    let mut list = List::new();
    list.append(format!("Authorization: {}", header).as_ref()).unwrap();
    let mut resp = Vec::new();
    try!(handle.url(uri.as_ref()));
    try!(handle.http_headers(list));
    try!(handle.post(true));
    try!(handle.post_field_size(body.len() as u64));
    {
        let mut transfer = handle.transfer();
        try!(transfer.read_function(|into| {
            let mut body = body.as_bytes();
            Ok(body.read(into).unwrap())
        }));
        try!(transfer.write_function(|data| {
            resp.extend_from_slice(data);
            Ok(data.len())
        }));
        try!(transfer.perform());
    }
    let code = try!(handle.response_code());
    if code != 200 {
        return Err(Error::HttpStatus(code))
    }
    Ok(resp)
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use super::encode;

    #[test]
    fn query() {
        let mut map = HashMap::new();
        let _ = map.insert("aaa".into(), "AAA".into());
        let _ = map.insert("bbbb".into(), "BBBB".into());
        let query = super::join_query(&map);
        assert_eq!("aaa=AAA&bbbb=BBBB", query);
    }

    #[test]
    fn test_encode() {
        let method = "GET";
        let uri = "http://oauthbin.com/v1/request-token";
        let encoded_uri = "http%3A%2F%2Foauthbin.com%2Fv1%2Frequest-token";
        let query = "oauth_consumer_key=key&oauth_nonce=s6HGl3GhmsDsmpgeLo6lGtKs7rQEzzsA&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1471445561&oauth_version=1.\
                     0";
        let encoded_query = "oauth_consumer_key%3Dkey%26oauth_nonce%3Ds6HGl3GhmsDsmpgeLo6lGtKs7rQEzzsA%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1471445561%26oauth_version%3D1.\
                             0";

        assert_eq!(encode(method), "GET");
        assert_eq!(encode(uri), encoded_uri);
        assert_eq!(encode(query), encoded_query);
    }
}
<|endoftext|>


<commit_before>//! A convenient wrapper for the [`c-ares`](http://c-ares.haxx.se) library.
//!
//! The [`c-ares` crate](https://crates.io/crates/c-ares) provides a safe
//! wrapper around the underlying C library, but it's relatively hard work to
//! use: the user needs to drive the polling of file descriptors according to
//! `c-ares` demands, which likely involves writing something close to a
//! full-blown event loop.
//!
//! This crate does that hard work for you so that the presented API is much
//! more straightforward.  Simply create a `Resolver`, and make your query -
//! providing a callback to be called when the query completes.
//!
//! This crate also provides a `FutureResolver`.  Queries on this object don't
//! take callbacks, and return `futures::Future` objects.
//!
//! (The API on the `FutureResolver` isn't _quite_ as complete as on the
//! `Resolver`.  For some types of query, the values returned by `c-ares` do
//! not have a long enough lifetime to be returned in a `Future`.  The relevant
//! functions are not supported by the `FutureResolver`.)
//!
//! Complete examples showing how to use the library can be found
//! [here](https://github.com/dimbleby/c-ares-resolver/tree/master/examples).
extern crate c_ares;
extern crate futures;
extern crate mio;

#[cfg(windows)]
extern crate winapi;

#[cfg(windows)]
extern crate ws2_32;

mod error;
mod eventloop;
mod futureresolver;
mod resolver;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

pub use error::Error;
pub use futureresolver::FutureResolver;
pub use resolver::{
    Options,
    Resolver,
};
<commit_msg>Tweak docs<commit_after>//! A convenient wrapper for the [`c-ares`](http://c-ares.haxx.se) library.
//!
//! The [`c-ares` crate](https://crates.io/crates/c-ares) provides a safe
//! wrapper around the underlying C library, but it's relatively hard work to
//! use: the user needs to drive the polling of file descriptors according to
//! `c-ares` demands, which likely involves writing something close to a
//! full-blown event loop.
//!
//! This crate does that hard work for you so that the presented API is much
//! more straightforward.  Simply create a `Resolver`, and make your query -
//! providing a callback to be called when the query completes.
//!
//! This crate also provides a `FutureResolver`.  Queries on this object
//! return `futures::Future` objects, and don't use callbacks.
//!
//! (The API on the `FutureResolver` isn't _quite_ as complete as on the
//! `Resolver`.  For some types of query, the values returned by `c-ares` do
//! not have a long enough lifetime to be returned in a `Future`.  The relevant
//! functions are not supported by the `FutureResolver`.)
//!
//! Complete examples showing how to use the library can be found
//! [here](https://github.com/dimbleby/c-ares-resolver/tree/master/examples).
extern crate c_ares;
extern crate futures;
extern crate mio;

#[cfg(windows)]
extern crate winapi;

#[cfg(windows)]
extern crate ws2_32;

mod error;
mod eventloop;
mod futureresolver;
mod resolver;

#[cfg(unix)]
mod unix;

#[cfg(windows)]
mod windows;

pub use error::Error;
pub use futureresolver::FutureResolver;
pub use resolver::{
    Options,
    Resolver,
};
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![no_std]

extern crate rlibc;

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
  loop {}
}

#[no_mangle]
pub extern fn rust_main() {
  let x = ["Hello", "World", "!"];
  let y = x;
  let test = (0..3).flat_map(|x| 0..x).zip(0..);
}

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! {loop{}}
<commit_msg>Hello from Rust<commit_after>#![feature(lang_items)]
#![no_std]

extern crate rlibc;

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
  loop {}
}

#[no_mangle]
pub extern fn rust_main() {
  let hello = b"Hello World!";
  let color_byte = 0x1f;

  let mut hello_colored = [color_byte; 24];
  for (i, char_byte) in hello.into_iter().enumerate() {
    hello_colored[i*2] = *char_byte;
  }

  let buffer_ptr = (0xb8000 + 1988) as *mut _;
  unsafe { *buffer_ptr = hello_colored };

  loop {}
}

#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] #[no_mangle] pub extern fn panic_fmt() -> ! {loop{}}
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]

extern crate num;

mod factor;
mod divisors;
mod multiplicative_functions;

pub use factor::*;
<commit_msg>Adds warning for missing docs.<commit_after>//! A library for factoring integers and computing various related functions.

#![warn(missing_docs)]

#![cfg_attr(all(feature = "bench", test), feature(test))]
#![cfg_attr(test, feature(test))]

extern crate num;

mod factor;
mod divisors;
mod multiplicative_functions;

pub use factor::*;
<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator library
//!

#![cfg_attr(nightly, feature(core_intrinsics))]
#![cfg_attr(nightly, feature(thread_local))]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
#![allow(deprecated)]
#![allow(non_fmt_panic)]

#[macro_use]
extern crate log;

mod detail;
mod gen_impl;
mod reg_context;
mod rt;
mod scope;
mod stack;
mod yield_;

pub use crate::gen_impl::{Generator, Gn};
pub use crate::rt::{get_local_data, is_generator, Error};
pub use crate::scope::Scope;
pub use crate::yield_::{
    co_get_yield, co_set_para, co_yield_with, done, get_yield, yield_, yield_from, yield_with,
};
<commit_msg>:pencil: public LocalGenerator<commit_after>//! # generator
//!
//! Rust generator library
//!

#![cfg_attr(nightly, feature(core_intrinsics))]
#![cfg_attr(nightly, feature(thread_local))]
#![cfg_attr(test, deny(warnings))]
#![deny(missing_docs)]
#![allow(deprecated)]
#![allow(non_fmt_panic)]

#[macro_use]
extern crate log;

mod detail;
mod gen_impl;
mod reg_context;
mod rt;
mod scope;
mod stack;
mod yield_;

pub use crate::gen_impl::{Generator, LocalGenerator, Gn};
pub use crate::rt::{get_local_data, is_generator, Error};
pub use crate::scope::Scope;
pub use crate::yield_::{
    co_get_yield, co_set_para, co_yield_with, done, get_yield, yield_, yield_from, yield_with,
};
<|endoftext|>


<commit_before>#![crate_name = "rusty-redis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::i64::parse_bytes;

// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(i64),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &str> {
    match buf.read_to_string() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_string()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_string()),
          RedisReplyError => self.reply = RedisError(nns.to_string()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: uint = 0;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n as uint;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_string().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc = argc + 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_string().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_string().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_string())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_string())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE: cleanup failed")
        },
        None => fail!("DELETE: cleanup failed")
      },
      Err(_) => fail!("DELETE: cleanup failed")
    }
  }

  #[test]
  fn test_nil_reply() {
    let mut context = ::RedisContext::connect("127.0.0.1", 6379);
    let r = context.command("GET", ["nomykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          super::RedisNil => return,
          _ => fail!("NIL: Didn't return correct reply type.")
        },
        None => fail!("NIL: Didn't return anything."),
      },
      Err(e) => fail!("{}", e)
    }
  }
}

<commit_msg>Fixed nightly breaking change, need to specify lifetimes in return types<commit_after>#![crate_name = "rusty-redis"]
#![desc = "A Rust client library for Redis based off hiredis"]
#![crate_type = "lib"]

use std::io::net::tcp::TcpStream;
use std::io::BufReader;
use std::i64::parse_bytes;

// TODO: need custom readline for bulk items

enum Global {
  RedisReaderMaxBuf = 1024 * 16
}

enum RedisReplyType {
  RedisReplyString,
  RedisReplyInteger,
  RedisReplyArray,
  RedisReplyNil,
  RedisReplyStatus,
  RedisReplyError
}

#[deriving(Clone)]
pub enum RedisObject {
  RedisString(String),
  RedisInteger(i64),
  RedisArray(Vec<RedisObject>),
  RedisNil,
  RedisStatus(String),
  RedisError(String)
}

enum RedisError {
  RedisNoError,
  RedisIoError,
  RedisProcessError
}

struct RedisReadTask {
  kind: RedisReplyType,
  elm: int,
  idx: int,
  obj: RedisObject
}

struct RedisReader {
  err: RedisError,
  errstr: String,
  buf: String, //this probably needs to be changed somehow
  reply: RedisObject,
  pos: uint, //might be needed in future, with dealing with multiple replies
  len: uint,
  rstack: [RedisReadTask, ..9],
  ridx: int
}

pub struct RedisContext {
  err: RedisError,
  errstr: String,
  tcpstream: TcpStream,
  flags: int, // async flag?
  obuf: String,
  reader: RedisReader
}

impl RedisReadTask {
  fn new() -> RedisReadTask {
    RedisReadTask {
      kind: RedisReplyNil,
      elm: -1,
      idx: -1,
      obj: RedisNil,
    }
  }
}

impl RedisReader {
  fn create_integer(&self, s: &str) -> Result<RedisObject, &'static str> {
    match parse_bytes(s.as_bytes(), 10) {
      Some(n) => Ok(RedisInteger(n)),
      None => Err("Invalid integer for create_integer")
    }
  }

  fn create_string(&self, mut buf: BufReader, len: uint) -> Result<RedisObject, &'static str> {
    match buf.read_to_string() {
      Ok(s) => {
        if len + 2 != s.len() { // include \r\n
          return Err("Invalid string for create_string: lengths do not matchup");
        }
        let ns = s.as_slice().trim();
        Ok(RedisString(ns.to_string()))
      },
      Err(_) => Err("Invalid string for create_string") // would be nice to not ignore this error
    }
  }

  fn process_line_item(&mut self) -> Result<(), &'static str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();

        match self.rstack[self.ridx as uint].kind {
          RedisReplyStatus => self.reply = RedisStatus(nns.to_string()),
          RedisReplyError => self.reply = RedisError(nns.to_string()),
          RedisReplyInteger => match self.create_integer(nns) {
            Ok(n) => self.reply = n,
            Err(e) => return Err(e)
          },
          _ => return Err("Invalid type for process_line_item")
        };
        Ok(())
      },
      Err(e) => Err(e.desc)
    }
  }

  fn process_bulk_item(&mut self) -> Result<(), &'static str> {
    let mut reader = BufReader::new(self.buf.as_bytes());

    reader.consume(1);
    match reader.read_line() {
      Ok(s) => {
        let ns = s.clone();
        let nns = ns.as_slice().trim();
        let mut len: uint = 0;
        match parse_bytes(nns.as_bytes(), 10){
          Some(n) => {
            if n == -1{
              self.rstack[self.ridx as uint].kind = RedisReplyNil;
            }
            else{
              len = n as uint;
            }
          },
          None => { return Err("Invalid length in reply for process_bulk_item") }
        };

        match self.rstack[self.ridx as uint].kind {
          RedisReplyString => match self.create_string(reader, len) {
            Ok(s) => self.reply = s,
            Err(e) => return Err(e)
          },
          RedisReplyNil => self.reply = RedisNil,
          _ => return Err("Invalid type for process_bulk_item")
        }
        Ok(())
      }
      Err(e) => Err(e.desc)
    }
  }

  fn process_multi_bulk_item(&mut self) -> Result<(), &'static str> {
    unimplemented!();
  }

  fn process_item(&mut self) -> Result<(), &'static str> {
    match self.rstack[self.ridx as uint].kind {
      RedisReplyError => self.process_line_item(),
      RedisReplyStatus => self.process_line_item(),
      RedisReplyInteger => self.process_line_item(),
      RedisReplyString => self.process_bulk_item(),
      RedisReplyArray => self.process_multi_bulk_item(),
      _ => Err("This should never happen")
    }
  }

  fn check_reply_type(&mut self) -> Result<(), &'static str> {
    let mut kind: RedisReplyType;
    let slice = self.buf.as_slice();
    match slice.char_at(0) {
      '-' => kind = RedisReplyError,
      '+' => kind = RedisReplyStatus,
      ':' => kind = RedisReplyInteger,
      '$' => kind = RedisReplyString,
      '*' => kind = RedisReplyArray,
      _ =>  return Err("Failed reading control byte")
    }

    self.rstack[self.ridx as uint].kind = kind;
    Ok(())
  }

  fn process_reply(&mut self) -> Result<Option<RedisObject>, &'static str> {
    if self.len == 0 {
      return Ok(None)
    }

    if self.ridx == -1 {
      self.ridx = 0;
    }

    while self.ridx >= 0 {
      match self.check_reply_type(){
        Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
        _ => match self.process_item() {
               Err(s) => { self.set_error(RedisProcessError, s); return Err(s) },
               _ => self.ridx = self.ridx - 1
             }
      }
    }
    self.buf.truncate(0);
    self.len = 0;
    Ok(Some(self.reply.clone()))
  }

  fn feed(&mut self, buf: &mut [u8], len: uint){
    let mut i = 0;
    while i < len {
      let c = buf[i].to_ascii();
      self.buf.push_char(c.to_char());
      i = i + 1;
    }
    self.len = len;
  }

  fn set_error(&mut self, err: RedisError, errstr: &'static str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn new() -> RedisReader {
    RedisReader {
      err: RedisNoError,
      errstr: String::new(),
      buf: String::new(),
      reply: RedisNil,
      pos: 0,
      len: 0,
      rstack: [RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new(),
               RedisReadTask::new()],
      ridx: -1
    }
  }
}

impl RedisContext {
  fn format_command(&self, cmd: &str, args: &[&str]) -> String {
    let mut argc: uint = 0;
    let mut c = String::new();
    let mut finalc = String::new();

    let mut len = cmd.len();
    c = c.append("$");
    c = c.append(len.to_string().as_slice());
    c = c.append("\r\n");
    c = c.append(cmd);
    c = c.append("\r\n");
    argc = argc + 1;

    for arg in args.iter(){
      len = arg.len();
      c = c.append("$");
      c = c.append(len.to_string().as_slice());
      c = c.append("\r\n");
      c = c.append(*arg);
      c = c.append("\r\n");
      argc = argc + 1;
    }
    finalc = finalc.append("*");
    finalc = finalc.append(argc.to_string().as_slice());
    finalc = finalc.append("\r\n");
    finalc = finalc.append(c.as_slice());
    finalc
  }

  fn set_error(&mut self, err: RedisError, errstr: &'static str){
    self.err = err;
    self.errstr = errstr.to_string();
  }

  fn check_error(&self) -> bool {
    match self.err {
      RedisNoError => false,
      _ => true
    }
  }

  fn get_reply_reader(&mut self) -> Result<Option<RedisObject>, &'static str> {
    self.reader.process_reply()
  }

  fn buffer_write(&mut self) {
    match self.tcpstream.write_str(self.obuf.as_slice()){
      Err(e) => { self.set_error(RedisIoError, e.desc ); }
      _ => ()
    }
  }

  fn buffer_read(&mut self) {
    let mut buf = [0, ..RedisReaderMaxBuf as uint];
    let res = self.tcpstream.read(buf);
    match res {
      Ok(s) => { self.reader.feed(buf, s); },
      Err(e) => { self.set_error(RedisIoError, e.desc); }
    }

  }

  fn block_for_reply(&mut self) -> Result<Option<RedisObject>, &'static str> {
    let o = try!(self.get_reply_reader());
    match o {
      Some(s) => Ok(Some(s)),
      None => {
        self.buffer_write();
        self.buffer_read();

        if self.check_error() {
          return Err("Error. Check error members.");
        }
        let o2 = try!(self.get_reply_reader());
        match o2{
          Some(s) => Ok(Some(s)),
          None => Err("No reply was found. Check error members.")
        }
      }
    }
  }

  pub fn connect(ip: &str, port: u16) -> RedisContext {
    RedisContext {
      err: RedisNoError,
      errstr: String::new(),
      tcpstream: match TcpStream::connect(ip, port) {
        Ok(s) => s,
        Err(e) => fail!(e.desc)
      },
      flags: 0,
      obuf: String::new(),
      reader: RedisReader::new()
    }
  }

  pub fn command(&mut self, cmd: &str, args: &[&str]) -> Result<Option<RedisObject>, &'static str> {
    self.obuf = self.format_command(cmd, args);
    self.block_for_reply()
  }
}

#[cfg(test)]
mod test {
  #[test]
  fn test_connect(){
    let _ = ::RedisContext::connect("127.0.0.1", 6379);
  }

  #[test]
  fn test_command(){
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("PING", []);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisStatus(s) => assert!(s.eq(&"PONG".to_string())),
          _ => fail!("Didn't return correct reply type.")
        },
        None => fail!("Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }
  }

  #[test]
  fn test_reply_types() {
    // Integer
    let mut c = ::RedisContext::connect("127.0.0.1", 6379);
    let r = c.command("APPEND", ["mykey", "test"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 4),
          _ => fail!("INTEGER: Didn't return correct reply type.")
        },
        None => fail!("INTEGER: Didn't return anything.")
      },
      Err(e) => fail!("INTEGER: {}", e)
    }

    // String
    let r = c.command("GET", ["mykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          ::RedisString(s) => assert!(s.eq(&"test".to_string())),
          _ => fail!("STRING: Didn't return correct reply type.")
        },
        None => fail!("STRING: Didn't return anything.")
      },
      Err(e) => fail!("{}", e)
    }

    // cleanup
    let r = c.command("DEL", ["mykey"]);

    match r {
      Ok(i) => match i {
        Some(i) => match i {
          ::RedisInteger(i) => assert!(i == 1),
          _ => fail!("DELETE: cleanup failed")
        },
        None => fail!("DELETE: cleanup failed")
      },
      Err(_) => fail!("DELETE: cleanup failed")
    }
  }

  #[test]
  fn test_nil_reply() {
    let mut context = ::RedisContext::connect("127.0.0.1", 6379);
    let r = context.command("GET", ["nomykey"]);

    match r {
      Ok(s) => match s {
        Some(s) => match s {
          super::RedisNil => return,
          _ => fail!("NIL: Didn't return correct reply type.")
        },
        None => fail!("NIL: Didn't return anything."),
      },
      Err(e) => fail!("{}", e)
    }
  }
}

<|endoftext|>


<commit_before>#![crate_name = "raft"]
#![crate_type="lib"]

#![allow(unstable)]
extern crate "rustc-serialize" as rustc_serialize;

use std::io::net::ip::SocketAddr;
use std::io::net::udp::UdpSocket;
use std::thread::Thread;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::str;
use rustc_serialize::json;

// The maximum size of the read buffer.
const BUFFER_SIZE: usize = 4096;

/// The Raft Distributed Consensus Algorithm requires two RPC calls to be available:
///
///   * `append_entries` which is used as both a heartbeat (with no payload) and the primary
///     interface for requests.
///   * `request_vote` which is used by candidates during campaigns to obtain a vote.
///
pub trait Raft {
    /// Returns (term, success)
    fn append_entries(term: usize, leader_id: usize, prev_log_index: usize,
                      prev_log_term: usize, entries: Vec<String>,
                      leader_commit: usize) -> (usize, bool);

    /// Returns (term, voteGranted)
    fn request_vote(term: usize, candidate_id: usize, last_log_index: usize,
                    last_log_term: usize) -> (usize, bool);
}

/// A `RaftNode` acts as a replicated state machine. The server's role in the cluster depends on it's
/// own status. It will maintain both volatile state (which can be safely lost) and persistent
/// state (which must be carefully stored and kept safe).
pub struct RaftNode {
    // Raft related.
    state: NodeState,
    persistent_state: PersistentState,
    volatile_state: VolatileState,
    // Auxilary Data.
    // TODO: This should probably be split off.
    // All nodes need to know this otherwise they can't effectively lead or hold elections.
    known_nodes: Vec<SocketAddr>,
    own_socket: SocketAddr,
}

/// The implementation of the RaftNode. In most use cases, creating a `RaftNode` should just be
/// done via `::new()`.
///
/// ```
/// use raft::RaftNode;
/// use std::io::net::ip::SocketAddr;
/// use std::io::net::ip::IpAddr::Ipv4Addr;
///
/// let my_node = RaftNode::new(
///     // This node's address.
///     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11111 },
///     // The list of nodes.
///     vec![
///     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11112 },
///     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11113 }
///     ]);
/// ```
impl RaftNode {
    /// Creates a new RaftNode with the neighbors specified.
    pub fn new(own_socket: SocketAddr, node_list: Vec<SocketAddr>) -> RaftNode {
        RaftNode {
            state: NodeState::Follower,
            persistent_state: PersistentState {
                current_term: 0, // TODO: Double Check.
                voted_for: 0,    // TODO: Better type?
                log: Vec::<String>::new(),
            },
            volatile_state: VolatileState {
                commit_index: 0,
                last_applied: 0,
            },
            known_nodes: node_list,
            own_socket: own_socket,
        }
    }
    /// Spins up a thread that listens and handles RPCs.
    pub fn spinup(&self) -> (Sender<(RemoteProcedureCall, SocketAddr)>, Receiver<String>) {
        let (entry_sender, entry_reciever) = channel::<String>();
        let (rpc_sender, rpc_reciever) = channel::<(RemoteProcedureCall, SocketAddr)>();
        // Need to clone the SocketAddr for lifetime reasons.
        let mut socket = UdpSocket::bind(self.own_socket)
            .unwrap(); // TODO: Can we do better?
        socket.set_read_timeout(Some(0));
        Thread::spawn(move || {
            let mut read_buffer = [0; BUFFER_SIZE];
            loop {
                match socket.recv_from(&mut read_buffer) {
                    Ok((num_read, source)) => {
                        let string_slice = str::from_utf8(read_buffer.slice_to_mut(num_read))
                            .unwrap(); // TODO: Can we do better?
                        let rpc = json::decode::<RemoteProcedureCall>(string_slice)
                            .unwrap(); // TODO: Can we do better?
                        entry_sender.send(format!("{:?}", rpc));
                    },
                    // TODO: Maybe need to handle this better.
                    Err(_) => (),
                }
                // Write anything in the channel out to the network.
                match rpc_reciever.try_recv() {
                    Ok((rpc, target)) => {
                        println!("Sending things!");
                        let encoded = json::encode::<RemoteProcedureCall>(&rpc);
                        socket.send_to(encoded.as_bytes(), target)
                            .unwrap(); // TODO: Can we do better?
                    },
                    // TODO: Maybe need to handle this better.
                    Err(_) => (),
                }
            }
        });
        (rpc_sender, entry_reciever)
    }
}

/// The RPC calls required by the Raft protocol.
impl Raft for RaftNode {
    /// Returns (term, success)
    fn append_entries(term: usize, leader_id: usize, prev_log_index: usize,
                      prev_log_term: usize, entries: Vec<String>,
                      leader_commit: usize) -> (usize, bool) {
        (0, false) // TODO: Implement
    }
    /// Returns (term, voteGranted)
    fn request_vote(term: usize, candidate_id: usize, last_log_index: usize,
                    last_log_term: usize) -> (usize, bool) {
        (0, false) // TODO: Implement
    }
}

/// Data interchange format for RPC calls.
#[derive(RustcEncodable, RustcDecodable, Show, Clone)]
pub enum RemoteProcedureCall {
    AppendEntries {
        term: usize,
        leader_id: usize,
        prev_log_index: usize,
        entries: Vec<String>,
        leader_commit: usize,
    },
    RequestVote {
        term: usize,
        candidate_id: usize,
        last_log_index: usize,
        last_log_term: usize,
    },
}

/// Nodes can either be:
///
///   * A `Follower`, which replicates AppendEntries requests and votes for it's leader.
///   * A `Leader`, which leads the cluster by serving incoming requests, ensuring data is
///     replicated, and issuing heartbeats..
///   * A `Candidate`, which campaigns in an election and may become a `Leader` (if it gets enough
///     votes) or a `Follower`, if it hears from a `Leader`.
pub enum NodeState {
    Follower,
    Leader(LeaderState),
    Candidate,
}

/// Persistent state
/// **Must be updated to stable storage before RPC response.**
pub struct PersistentState {
    current_term: usize,
    voted_for: usize, // Better way? Can we use a IpAddr?
    log: Vec<String>,
}

/// Volatile state
pub struct VolatileState {
    commit_index: usize,
    last_applied: usize
}

/// Leader Only
/// **Reinitialized after election.**
pub struct LeaderState {
    next_index: Vec<usize>,
    match_index: Vec<usize>
}

#[cfg(test)]
mod tests {
    use std::io::net::ip::SocketAddr;
    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::IpAddr::Ipv4Addr;
    use std::thread::Thread;
    use rustc_serialize::json;
    use std::sync::mpsc::{channel, Sender, Receiver};
    use std::str;
    use super::*;

    #[test]
    fn accepts_request_vote() {
        let send_addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11111 };
        let recieve_addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11112 };
        // Create the node.
        let send_node = RaftNode::new(
            send_addr, // The node's address.
            vec![
            recieve_addr, // The neighbor.
            ]);
        let recieve_node = RaftNode::new(
            recieve_addr, // The node's address.
            vec![
            send_addr, // The neighbor.
            ]);
        // Start up the node.
        let (_, log_reciever) = recieve_node.spinup();
        let (rpc_sender, _) = send_node.spinup();
        // Make a test send to that port.
        let test_value = RemoteProcedureCall::RequestVote {
            term: 0,
            candidate_id: 0,
            last_log_index: 0,
            last_log_term: 0,
        };
        rpc_sender.send((test_value.clone(), recieve_addr)).unwrap();
        // Get the result.
        let event = log_reciever.recv().unwrap();
        assert_eq!(event, format!("{:?}", test_value));
    }

}
<commit_msg>Use generics!<commit_after>#![crate_name = "raft"]
#![crate_type="lib"]

#![allow(unstable)]
extern crate "rustc-serialize" as rustc_serialize;

use std::io::net::ip::SocketAddr;
use std::io::net::udp::UdpSocket;
use std::thread::Thread;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::str;
use rustc_serialize::{json, Encodable, Decodable};
use RemoteProcedureCall::{AppendEntries, RequestVote};

// The maximum size of the read buffer.
const BUFFER_SIZE: usize = 4096;

/// The Raft Distributed Consensus Algorithm requires two RPC calls to be available:
///
///   * `append_entries` which is used as both a heartbeat (with no payload) and the primary
///     interface for requests.
///   * `request_vote` which is used by candidates during campaigns to obtain a vote.
///
pub trait Raft<T: Encodable + Decodable + Send + Clone> {
    /// Returns (term, success)
    fn append_entries(term: usize, leader_id: usize, prev_log_index: usize,
                      prev_log_term: usize, entries: Vec<T>,
                      leader_commit: usize) -> (usize, bool);

    /// Returns (term, voteGranted)
    fn request_vote(term: usize, candidate_id: usize, last_log_index: usize,
                    last_log_term: usize) -> (usize, bool);
}

/// A `RaftNode` acts as a replicated state machine. The server's role in the cluster depends on it's
/// own status. It will maintain both volatile state (which can be safely lost) and persistent
/// state (which must be carefully stored and kept safe).
pub struct RaftNode<T: Encodable + Decodable + Send + Clone> {
    // Raft related.
    state: NodeState,
    persistent_state: PersistentState<T>,
    volatile_state: VolatileState,
    // Auxilary Data.
    // TODO: This should probably be split off.
    // All nodes need to know this otherwise they can't effectively lead or hold elections.
    known_nodes: Vec<SocketAddr>,
    own_socket: SocketAddr,
}

/// The implementation of the RaftNode. In most use cases, creating a `RaftNode` should just be
/// done via `::new()`.
///
/// ```
/// use raft::RaftNode;
/// use std::io::net::ip::SocketAddr;
/// use std::io::net::ip::IpAddr::Ipv4Addr;
///
/// let my_node = RaftNode::<String>::new(
///     // This node's address.
///     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11111 },
///     // The list of nodes.
///     vec![
///     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11112 },
///     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11113 }
///     ]);
/// ```
impl<T: Encodable + Decodable + Send + Clone> RaftNode<T> {
    /// Creates a new RaftNode with the neighbors specified.
    pub fn new(own_socket: SocketAddr, node_list: Vec<SocketAddr>) -> RaftNode<T> {
        RaftNode {
            state: NodeState::Follower,
            persistent_state: PersistentState {
                current_term: 0, // TODO: Double Check.
                voted_for: 0,    // TODO: Better type?
                log: Vec::<T>::new(),
            },
            volatile_state: VolatileState {
                commit_index: 0,
                last_applied: 0,
            },
            known_nodes: node_list,
            own_socket: own_socket,
        }
    }
    /// Spins up a thread that listens and handles RPCs.
    pub fn spinup(&self) -> (Sender<(RemoteProcedureCall<T>, SocketAddr)>, Receiver<T>) {
        let (entry_sender, entry_reciever) = channel::<T>();
        let (rpc_sender, rpc_reciever) = channel::<(RemoteProcedureCall<T>, SocketAddr)>();
        // Need to clone the SocketAddr for lifetime reasons.
        let mut socket = UdpSocket::bind(self.own_socket)
            .unwrap(); // TODO: Can we do better?
        socket.set_read_timeout(Some(0));
        Thread::spawn(move || {
            let mut read_buffer = [0; BUFFER_SIZE];
            loop {
                // Read anything from the socket and handle it.
                match socket.recv_from(&mut read_buffer) {
                    Ok((num_read, source)) => {
                        let string_slice = str::from_utf8(read_buffer.slice_to_mut(num_read))
                            .unwrap(); // TODO: Can we do better?
                        let mut rpc = json::decode::<RemoteProcedureCall<T>>(string_slice)
                            .unwrap(); // TODO: Can we do better?
                        match rpc {
                            AppendEntries { entries: mut entries, .. } => {
                                // TODO: Log data properly.
                                for entry in entries.iter_mut() {
                                    entry_sender.send(entry.clone());
                                }
                            },
                            RequestVote { .. } => {
                                // TODO: Do something.
                            },
                        }
                    },
                    // TODO: Maybe need to handle this better.
                    Err(_) => (),
                }
                // Write anything in the channel out to the network.
                match rpc_reciever.try_recv() {
                    Ok((rpc, target)) => {
                        println!("Sending things!");
                        let encoded = json::encode::<RemoteProcedureCall<T>>(&rpc);
                        socket.send_to(encoded.as_bytes(), target)
                            .unwrap(); // TODO: Can we do better?
                    },
                    // TODO: Maybe need to handle this better.
                    Err(_) => (),
                }
            }
        });
        (rpc_sender, entry_reciever)
    }
}

/// The RPC calls required by the Raft protocol.
impl<T: Encodable + Decodable + Send + Clone> Raft<T> for RaftNode<T> {
    /// Returns (term, success)
    fn append_entries(term: usize, leader_id: usize, prev_log_index: usize,
                      prev_log_term: usize, entries: Vec<T>,
                      leader_commit: usize) -> (usize, bool) {
        (0, false) // TODO: Implement
    }
    /// Returns (term, voteGranted)
    fn request_vote(term: usize, candidate_id: usize, last_log_index: usize,
                    last_log_term: usize) -> (usize, bool) {
        (0, false) // TODO: Implement
    }
}

/// Data interchange format for RPC calls.
#[derive(RustcEncodable, RustcDecodable, Show, Clone)]
pub enum RemoteProcedureCall<T> {
    AppendEntries {
        term: usize,
        leader_id: usize,
        prev_log_index: usize,
        entries: Vec<T>,
        leader_commit: usize,
    },
    RequestVote {
        term: usize,
        candidate_id: usize,
        last_log_index: usize,
        last_log_term: usize,
    },
}

/// Nodes can either be:
///
///   * A `Follower`, which replicates AppendEntries requests and votes for it's leader.
///   * A `Leader`, which leads the cluster by serving incoming requests, ensuring data is
///     replicated, and issuing heartbeats..
///   * A `Candidate`, which campaigns in an election and may become a `Leader` (if it gets enough
///     votes) or a `Follower`, if it hears from a `Leader`.
pub enum NodeState {
    Follower,
    Leader(LeaderState),
    Candidate,
}

/// Persistent state
/// **Must be updated to stable storage before RPC response.**
pub struct PersistentState<T: Encodable + Decodable + Send + Clone> {
    current_term: usize,
    voted_for: usize, // Better way? Can we use a IpAddr?
    log: Vec<T>,
}

/// Volatile state
pub struct VolatileState {
    commit_index: usize,
    last_applied: usize
}

/// Leader Only
/// **Reinitialized after election.**
pub struct LeaderState {
    next_index: Vec<usize>,
    match_index: Vec<usize>
}

#[cfg(test)]
mod tests {
    use std::io::net::ip::SocketAddr;
    use std::io::net::udp::UdpSocket;
    use std::io::net::ip::IpAddr::Ipv4Addr;
    use std::thread::Thread;
    use rustc_serialize::json;
    use std::sync::mpsc::{channel, Sender, Receiver};
    use std::str;
    use super::*;

    #[test]
    fn basic_test() {
        let send_addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11111 };
        let recieve_addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 11112 };
        // Create the node.
        let send_node = RaftNode::<String>::new(
            send_addr, // The node's address.
            vec![
            recieve_addr, // The neighbor.
            ]);
        let recieve_node = RaftNode::<String>::new(
            recieve_addr, // The node's address.
            vec![
            send_addr, // The neighbor.
            ]);
        // Start up the node.
        let (_, log_reciever) = recieve_node.spinup();
        let (rpc_sender, _) = send_node.spinup();
        // Make a test send to that port.
        let test_value = RemoteProcedureCall::AppendEntries {
            term: 0,
            leader_id: 0,
            prev_log_index: 0,
            entries: vec!["foo".to_string()],
            leader_commit: 0,
        };
        rpc_sender.send((test_value.clone(), recieve_addr)).unwrap();
        // Get the result.
        let event = log_reciever.recv().unwrap();
        assert_eq!(event, "foo".to_string());
    }

}
<|endoftext|>