<commit_before>use nom::{multispace, space};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, unsigned_number, statement_terminator, table_list};
use parser::ConditionExpression;

use condition::*;

#[derive(Clone, Debug, PartialEq)]
pub struct GroupByClause {
    columns: Vec<String>,
    having: String, // XXX(malte): should this be an arbitrary expr?
}

#[derive(Clone, Debug, PartialEq)]
pub struct LimitClause {
    limit: u64,
    offset: u64,
}

#[derive(Clone, Debug, PartialEq)]
enum OrderType {
    //   OrderAscending,
    //   OrderDescending,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderClause {
    order_type: OrderType,
    order_cols: Vec<String>, // TODO(malte): can this be an arbitrary expr?
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct SelectStatement {
    pub table: String,
    pub distinct: bool,
    pub fields: Vec<String>,
    pub where_clause: Option<ConditionExpression>,
    pub group_by: Option<GroupByClause>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse LIMIT clause
named!(limit_clause<&[u8], LimitClause>,
    chain!(
        space ~
        caseless_tag!("limit") ~
        space ~
        limit_val: unsigned_number ~
        space? ~
        offset_val: opt!(chain!(
                caseless_tag!("offset") ~
                space ~
                val: unsigned_number,
                || { val }
            )
        ),
    || {
        LimitClause {
            limit: limit_val,
            offset: match offset_val {
                None => 0,
                Some(v) => v,
            },
        }
    })
);

named!(order_clause<&[u8], OrderClause>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("order by") ~
        multispace ~
        order_expr: field_list ~
        ordering: opt!(
            alt_complete!(
                  map!(caseless_tag!("desc"), |_| OrderType::OrderDescending)
                | map!(caseless_tag!("asc"), |_| OrderType::OrderAscending)
            )
        ),
    || {
        OrderClause {
            cols: order_expr.iter().map(|e| String::from(*e)).collect(),
            order: match ordering {
                None => OrderType::OrderAscending,
                Some(ref o) => o.clone(),
            },
        }
    })
));

/// Parse WHERE clause of a selection
named!(where_clause<&[u8], ConditionExpression>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("where") ~
        multispace ~
        cond: condition_expr,
        || { cond }
    )
));

/// Parse rule for a SQL selection query.
/// TODO(malte): support nested queries as selection targets
named!(pub selection<&[u8], SelectStatement>,
    chain!(
        caseless_tag!("select") ~
        space ~
        distinct: opt!(caseless_tag!("distinct")) ~
        space? ~
        fields: field_list ~
        delimited!(opt!(multispace), caseless_tag!("from"), opt!(multispace)) ~
        tables: table_list ~
        cond: opt!(where_clause) ~
        order: opt!(order_clause) ~
        limit: opt!(limit_clause) ~
        statement_terminator,
        || {
            SelectStatement {
                tables: tables.iter().map(|t| String::from(*t)).collect(),
                distinct: distinct.is_some(),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
                where_clause: cond,
                group_by: None,
                order: order,
                limit: limit,
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use common::Operator;
    use parser::{ConditionBase, ConditionExpression, ConditionTree};

    #[test]
    fn simple_select() {
        let qstring = "SELECT id, name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn select_all() {
        let qstring = "SELECT * FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn spaces_optional() {
        let qstring = "SELECT id,name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn case_sensitivity() {
        let qstring_lc = "select id, name from users;";
        let qstring_uc = "SELECT id, name FROM users;";

        assert_eq!(selection(qstring_lc.as_bytes()).unwrap(),
                   selection(qstring_uc.as_bytes()).unwrap());
    }

    #[test]
    fn termination() {
        let qstring_sem = "select id, name from users;";
        let qstring_linebreak = "select id, name from users\n";

        assert_eq!(selection(qstring_sem.as_bytes()).unwrap(),
                   selection(qstring_linebreak.as_bytes()).unwrap());
    }

    #[test]
    fn where_clause() {
        let qstring = "select * from ContactInfo where email=?;";

        let res = selection(qstring.as_bytes());

        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("email"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("ContactInfo"),
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn limit_clause() {
        let qstring1 = "select * from users limit 10\n";
        let qstring2 = "select * from users limit 10 offset 10\n";

        let expected_lim1 = LimitClause {
            limit: 10,
            offset: 0,
        };
        let expected_lim2 = LimitClause {
            limit: 10,
            offset: 10,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        assert_eq!(res1.unwrap().1.limit, Some(expected_lim1));
        assert_eq!(res2.unwrap().1.limit, Some(expected_lim2));
    }

    #[test]
    fn table_alias() {
        let qstring1 = "select * from PaperTag as t;";
        // let qstring2 = "select * from PaperTag t;";

        let res1 = selection(qstring1.as_bytes());
        assert_eq!(res1.clone().unwrap().1,
                   SelectStatement {
                       table: String::from("PaperTag"),
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
        // let res2 = selection(qstring2.as_bytes());
        // assert_eq!(res1.unwrap().1, res2.unwrap().1);
    }

    #[test]
    fn distinct() {
        let qstring = "select distinct tag from PaperTag where paperId=?;";

        let res = selection(qstring.as_bytes());
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("PaperTag"),
                       distinct: true,
                       fields: vec!["tag".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn simple_condition_expr() {
        let qstring = "select infoJson from PaperStorage where paperId=? and paperStorageId=?;";

        let res = selection(qstring.as_bytes());

        let left_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let right_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperStorageId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let expected_where_cond = Some(ConditionExpression::LogicalOp(ConditionTree {
            left: left_comp,
            right: right_comp,
            operator: String::from("and"),
        }));
        println!("res: {:#?}", res);
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("PaperStorage"),
                       fields: vec!["infoJson".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }
}
<commit_msg>Support ORDER BY clause on selections<commit_after>use nom::{multispace, space};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;

use common::{field_list, unsigned_number, statement_terminator, table_list};
use parser::ConditionExpression;

use condition::*;

#[derive(Clone, Debug, PartialEq)]
pub struct GroupByClause {
    columns: Vec<String>,
    having: String, // XXX(malte): should this be an arbitrary expr?
}

#[derive(Clone, Debug, PartialEq)]
pub struct LimitClause {
    limit: u64,
    offset: u64,
}

#[derive(Clone, Debug, PartialEq)]
pub enum OrderType {
    OrderAscending,
    OrderDescending,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderClause {
    cols: Vec<String>, // TODO(malte): can this be an arbitrary expr?
    order: OrderType,
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct SelectStatement {
    pub table: String,
    pub distinct: bool,
    pub fields: Vec<String>,
    pub where_clause: Option<ConditionExpression>,
    pub group_by: Option<GroupByClause>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse LIMIT clause
named!(limit_clause<&[u8], LimitClause>,
    chain!(
        space ~
        caseless_tag!("limit") ~
        space ~
        limit_val: unsigned_number ~
        space? ~
        offset_val: opt!(chain!(
                caseless_tag!("offset") ~
                space ~
                val: unsigned_number,
                || { val }
            )
        ),
    || {
        LimitClause {
            limit: limit_val,
            offset: match offset_val {
                None => 0,
                Some(v) => v,
            },
        }
    })
);

named!(order_clause<&[u8], OrderClause>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("order by") ~
        multispace ~
        order_expr: field_list ~
        ordering: opt!(
            alt_complete!(
                  map!(caseless_tag!("desc"), |_| OrderType::OrderDescending)
                | map!(caseless_tag!("asc"), |_| OrderType::OrderAscending)
            )
        ),
    || {
        OrderClause {
            cols: order_expr.iter().map(|e| String::from(*e)).collect(),
            order: match ordering {
                None => OrderType::OrderAscending,
                Some(ref o) => o.clone(),
            },
        }
    })
));

/// Parse WHERE clause of a selection
named!(where_clause<&[u8], ConditionExpression>,
    dbg_dmp!(chain!(
        multispace? ~
        caseless_tag!("where") ~
        multispace ~
        cond: condition_expr,
        || { cond }
    )
));

/// Parse rule for a SQL selection query.
/// TODO(malte): support nested queries as selection targets
named!(pub selection<&[u8], SelectStatement>,
    chain!(
        caseless_tag!("select") ~
        space ~
        distinct: opt!(caseless_tag!("distinct")) ~
        space? ~
        fields: field_list ~
        delimited!(opt!(multispace), caseless_tag!("from"), opt!(multispace)) ~
        tables: table_list ~
        cond: opt!(where_clause) ~
        order: opt!(order_clause) ~
        limit: opt!(limit_clause) ~
        statement_terminator,
        || {
            SelectStatement {
                tables: tables.iter().map(|t| String::from(*t)).collect(),
                distinct: distinct.is_some(),
                fields: fields.iter().map(|s| String::from(*s)).collect(),
                where_clause: cond,
                group_by: None,
                order: order,
                limit: limit,
            }
        }
    )
);

#[cfg(test)]
mod tests {
    use super::*;
    use common::Operator;
    use parser::{ConditionBase, ConditionExpression, ConditionTree};

    #[test]
    fn simple_select() {
        let qstring = "SELECT id, name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn select_all() {
        let qstring = "SELECT * FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn spaces_optional() {
        let qstring = "SELECT id,name FROM users;";

        let res = selection(qstring.as_bytes());
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("users"),
                       fields: vec!["id".into(), "name".into()],
                       ..Default::default()
                   });
    }

    #[test]
    fn case_sensitivity() {
        let qstring_lc = "select id, name from users;";
        let qstring_uc = "SELECT id, name FROM users;";

        assert_eq!(selection(qstring_lc.as_bytes()).unwrap(),
                   selection(qstring_uc.as_bytes()).unwrap());
    }

    #[test]
    fn termination() {
        let qstring_sem = "select id, name from users;";
        let qstring_linebreak = "select id, name from users\n";

        assert_eq!(selection(qstring_sem.as_bytes()).unwrap(),
                   selection(qstring_linebreak.as_bytes()).unwrap());
    }

    #[test]
    fn where_clause() {
        let qstring = "select * from ContactInfo where email=?;";

        let res = selection(qstring.as_bytes());

        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("email"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("ContactInfo"),
                       fields: vec!["ALL".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn limit_clause() {
        let qstring1 = "select * from users limit 10\n";
        let qstring2 = "select * from users limit 10 offset 10\n";

        let expected_lim1 = LimitClause {
            limit: 10,
            offset: 0,
        };
        let expected_lim2 = LimitClause {
            limit: 10,
            offset: 10,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        assert_eq!(res1.unwrap().1.limit, Some(expected_lim1));
        assert_eq!(res2.unwrap().1.limit, Some(expected_lim2));
    }

    #[test]
    fn order_clause() {
        let qstring1 = "select * from users order by name desc\n";
        let qstring2 = "select * from users order by name, age desc\n";
        let qstring3 = "select * from users order by name\n";

        let expected_ord1 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord2 = OrderClause {
            cols: vec!["name".into(), "age".into()],
            order: OrderType::OrderDescending,
        };
        let expected_ord3 = OrderClause {
            cols: vec!["name".into()],
            order: OrderType::OrderAscending,
        };

        let res1 = selection(qstring1.as_bytes());
        let res2 = selection(qstring2.as_bytes());
        let res3 = selection(qstring3.as_bytes());
        assert_eq!(res1.unwrap().1.order, Some(expected_ord1));
        assert_eq!(res2.unwrap().1.order, Some(expected_ord2));
        assert_eq!(res3.unwrap().1.order, Some(expected_ord3));
    }

    #[test]
    fn table_alias() {
        let qstring1 = "select * from PaperTag as t;";
        // let qstring2 = "select * from PaperTag t;";

        let res1 = selection(qstring1.as_bytes());
        assert_eq!(res1.clone().unwrap().1,
                   SelectStatement {
                       table: String::from("PaperTag"),
                       fields: vec!["ALL".into()],
                       ..Default::default()
                   });
        // let res2 = selection(qstring2.as_bytes());
        // assert_eq!(res1.unwrap().1, res2.unwrap().1);
    }

    #[test]
    fn distinct() {
        let qstring = "select distinct tag from PaperTag where paperId=?;";

        let res = selection(qstring.as_bytes());
        let expected_where_cond = Some(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: Operator::Equal,
        }));
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("PaperTag"),
                       distinct: true,
                       fields: vec!["tag".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }

    #[test]
    fn simple_condition_expr() {
        let qstring = "select infoJson from PaperStorage where paperId=? and paperStorageId=?;";

        let res = selection(qstring.as_bytes());

        let left_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let right_comp = Some(Box::new(ConditionExpression::ComparisonOp(ConditionTree {
            left:
                Some(Box::new(ConditionExpression::Base(ConditionBase::Field(String::from("paperStorageId"))))),
            right: Some(Box::new(ConditionExpression::Base(ConditionBase::Placeholder))),
            operator: String::from("="),
        })));
        let expected_where_cond = Some(ConditionExpression::LogicalOp(ConditionTree {
            left: left_comp,
            right: right_comp,
            operator: String::from("and"),
        }));
        println!("res: {:#?}", res);
        assert_eq!(res.unwrap().1,
                   SelectStatement {
                       table: String::from("PaperStorage"),
                       fields: vec!["infoJson".into()],
                       where_clause: expected_where_cond,
                       ..Default::default()
                   });
    }
}
<|endoftext|>


<commit_before>use clap;
use info::{DiscoveryServiceInfo, EnvironmentInfo};
use serde_json::Value;

pub fn read_only_environment(info: &DiscoveryServiceInfo) -> EnvironmentInfo {
    let read_only: Vec<EnvironmentInfo> =
        info.environments
            .clone()
            .into_iter()
            .filter({
            |env| env.environment["read_only"].as_bool().unwrap_or(false)
        })
            .collect();

    assert!(
        read_only.len() <= 1,
        format!("Multiple read only environments found {:?}", read_only)
    );

    read_only.first()
             .expect("No read only environment found")
             .clone()
}

pub fn writable_environment(info: &DiscoveryServiceInfo) -> EnvironmentInfo {
    let writables: Vec<EnvironmentInfo> =
        info.environments
            .clone()
            .into_iter()
            .filter({
            |env| !env.environment["read_only"].as_bool().unwrap_or(true)
        })
            .collect();

    assert!(
        writables.len() <= 1,
        format!("Multiple writable environments found {:?}", writables)
    );

    writables.first()
             .expect("No writable environment found")
             .clone()
}

pub fn oldest_collection(env: &EnvironmentInfo) -> Value {
    env.collections
       .first()
       .expect("No collections found")
       .clone()
}

pub fn newest_collection(env: &EnvironmentInfo) -> Value {
    env.collections
       .last()
       .expect("No collections found")
       .clone()
}

pub fn collection_with_name(env: &EnvironmentInfo, name: &str) -> Value {
    let f: Vec<Value> = env.collections
                           .clone()
                           .into_iter()
                           .filter({
        |i| i["name"].as_str() == Some(name)
    })
                           .collect();
    assert_eq!(f.len(), 1, "No collection matched {}", name);
    f.first()
     .expect("Internal error: count=1, but no last!?")
     .clone()
}

pub fn collection_with_id(env: &EnvironmentInfo, id: &str) -> Value {
    let f: Vec<Value> = env.collections
                           .clone()
                           .into_iter()
                           .filter({
        |i| i["collection_id"].as_str() == Some(id)
    })
                           .collect();
    assert_eq!(f.len(), 1, "No collection matched {}", id);
    f.last()
     .expect("Internal error: count=1, but no last!?")
     .clone()
}

pub fn select_collection(
    env_info: &EnvironmentInfo,
    matches: &clap::ArgMatches,
) -> Value {
    if matches.is_present("named") {
        collection_with_name(env_info, matches.value_of("named").unwrap())
    } else if matches.is_present("id") {
        collection_with_id(env_info, matches.value_of("id").unwrap())
    } else if matches.is_present("oldest") {
        oldest_collection(env_info)
    } else {
        newest_collection(env_info)
    }
}

pub fn configuration_with_name(
    env: &EnvironmentInfo,
    configuration_name: &str,
) -> Value {
    env.configurations
       .clone()
       .into_iter()
       .filter({
        |c| c["name"].as_str() == Some(configuration_name)
    })
       .last()
       .expect("No configuration found")
       .clone()
}

pub fn configuration_with_id(
    env: &EnvironmentInfo,
    configuration_id: &str,
) -> Value {
    env.configurations
       .clone()
       .into_iter()
       .filter({
        |c| c["configuration_id"].as_str() == Some(configuration_id)
    })
       .last()
       .expect("No configuration found")
       .clone()
}

pub fn oldest_configuration(env: &EnvironmentInfo) -> Value {
    env.configurations
       .first()
       .expect("No configurations found")
       .clone()
}

pub fn newest_configuration(env: &EnvironmentInfo) -> Value {
    env.configurations
       .last()
       .expect("No configurations found")
       .clone()
}

pub fn select_configuration(
    env_info: &EnvironmentInfo,
    matches: &clap::ArgMatches,
) -> Value {
    if matches.is_present("named") {
        configuration_with_name(env_info, matches.value_of("named").unwrap())
    } else if matches.is_present("id") {
        configuration_with_id(env_info, matches.value_of("id").unwrap())
    } else if matches.is_present("oldest") {
        oldest_configuration(env_info)
    } else {
        newest_configuration(env_info)
    }
}
<commit_msg>Bug fix: avoid panic when no config<commit_after>use clap;
use info::{DiscoveryServiceInfo, EnvironmentInfo};
use serde_json::Value;

pub fn read_only_environment(info: &DiscoveryServiceInfo) -> EnvironmentInfo {
    let read_only: Vec<EnvironmentInfo> =
        info.environments
            .clone()
            .into_iter()
            .filter({
            |env| env.environment["read_only"].as_bool().unwrap_or(false)
        })
            .collect();

    assert!(
        read_only.len() <= 1,
        format!("Multiple read only environments found {:?}", read_only)
    );

    read_only.first()
             .expect("No read only environment found")
             .clone()
}

pub fn writable_environment(info: &DiscoveryServiceInfo) -> EnvironmentInfo {
    let writables: Vec<EnvironmentInfo> =
        info.environments
            .clone()
            .into_iter()
            .filter({
            |env| !env.environment["read_only"].as_bool().unwrap_or(true)
        })
            .collect();

    assert!(
        writables.len() <= 1,
        format!("Multiple writable environments found {:?}", writables)
    );

    writables.first()
             .expect("No writable environment found")
             .clone()
}

pub fn oldest_collection(env: &EnvironmentInfo) -> Value {
    env.collections
       .first()
       .expect("No collections found")
       .clone()
}

pub fn newest_collection(env: &EnvironmentInfo) -> Value {
    env.collections
       .last()
       .expect("No collections found")
       .clone()
}

pub fn collection_with_name(env: &EnvironmentInfo, name: &str) -> Value {
    let f: Vec<Value> = env.collections
                           .clone()
                           .into_iter()
                           .filter({
        |i| i["name"].as_str() == Some(name)
    })
                           .collect();
    assert_eq!(f.len(), 1, "No collection matched {}", name);
    f.first()
     .expect("Internal error: count=1, but no last!?")
     .clone()
}

pub fn collection_with_id(env: &EnvironmentInfo, id: &str) -> Value {
    let f: Vec<Value> = env.collections
                           .clone()
                           .into_iter()
                           .filter({
        |i| i["collection_id"].as_str() == Some(id)
    })
                           .collect();
    assert_eq!(f.len(), 1, "No collection matched {}", id);
    f.last()
     .expect("Internal error: count=1, but no last!?")
     .clone()
}

pub fn select_collection(
    env_info: &EnvironmentInfo,
    matches: &clap::ArgMatches,
) -> Value {
    if matches.is_present("named") {
        collection_with_name(env_info, matches.value_of("named").unwrap())
    } else if matches.is_present("id") {
        collection_with_id(env_info, matches.value_of("id").unwrap())
    } else if matches.is_present("oldest") {
        oldest_collection(env_info)
    } else {
        newest_collection(env_info)
    }
}

pub fn configuration_with_name(
    env: &EnvironmentInfo,
    configuration_name: &str,
) -> Value {
    env.configurations
       .clone()
       .into_iter()
       .filter({
        |c| c["name"].as_str() == Some(configuration_name)
    })
       .last()
       .unwrap_or(Value::Null)
       .clone()
}

pub fn configuration_with_id(
    env: &EnvironmentInfo,
    configuration_id: &str,
) -> Value {
    env.configurations
       .clone()
       .into_iter()
       .filter({
        |c| c["configuration_id"].as_str() == Some(configuration_id)
    })
       .last()
       .unwrap_or(Value::Null)
       .clone()
}

pub fn oldest_configuration(env: &EnvironmentInfo) -> Value {
    env.configurations
       .first()
       .expect("No configurations found")
       .clone()
}

pub fn newest_configuration(env: &EnvironmentInfo) -> Value {
    env.configurations
       .last()
       .expect("No configurations found")
       .clone()
}

pub fn select_configuration(
    env_info: &EnvironmentInfo,
    matches: &clap::ArgMatches,
) -> Value {
    if matches.is_present("named") {
        configuration_with_name(env_info, matches.value_of("named").unwrap())
    } else if matches.is_present("id") {
        configuration_with_id(env_info, matches.value_of("id").unwrap())
    } else if matches.is_present("oldest") {
        oldest_configuration(env_info)
    } else {
        newest_configuration(env_info)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017-2019 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! Implements the Roughenough server functionality.
//!

use hex;
use std::io::ErrorKind;
use std::net::SocketAddr;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::io::Write;
use time;

use byteorder::{LittleEndian, WriteBytesExt};

use humansize::{FileSize, file_size_opts as fsopts};

use mio::net::{TcpListener, UdpSocket};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio::tcp::Shutdown;
use mio_extras::timer::Timer;

use crate::config::ServerConfig;
use crate::key::{LongTermKey, OnlineKey};
use crate::kms;
use crate::merkle::MerkleTree;
use crate::{Error, RtMessage, Tag, MIN_REQUEST_LENGTH};
use crate::stats::{ServerStats, PerClientStats};

macro_rules! check_ctrlc {
    ($keep_running:expr) => {
        if !$keep_running.load(Ordering::Acquire) {
            warn!("Ctrl-C caught, exiting...");
            return true;
        }
    };
}

// mio event registrations
const MESSAGE: Token = Token(0);
const STATUS: Token = Token(1);
const HEALTH_CHECK: Token = Token(2);

// Canned response to health check request
const HTTP_RESPONSE: &str = "HTTP/1.1 200 OK\nContent-Length: 0\nConnection: close\n\n";

/// The main Roughenough server instance.
///
/// The [ServerConfig](../config/trait.ServerConfig.html) trait specifies the required and optional
/// parameters available for configuring a Roughenoguh server instance.
///
/// Implementations of `ServerConfig` obtain configurations from different back-end sources
/// such as files or environment variables.
///
/// See [the config module](../config/index.html) for more information.
///
pub struct Server {
    config: Box<dyn ServerConfig>,
    online_key: OnlineKey,
    cert_bytes: Vec<u8>,

    socket: UdpSocket,
    health_listener: Option<TcpListener>,
    keep_running: Arc<AtomicBool>,
    poll_duration: Option<Duration>,
    timer: Timer<()>,
    poll: Poll,
    merkle: MerkleTree,
    requests: Vec<(Vec<u8>, SocketAddr)>,
    buf: [u8; 65_536],

    public_key: String,

    // Used to send requests to ourselves in fuzzing mode
    #[cfg(fuzzing)]
    fake_client_socket: UdpSocket,

    stats: PerClientStats,
}

impl Server {
    ///
    /// Create a new server instance from the provided
    /// [`ServerConfig`](../config/trait.ServerConfig.html) trait object instance.
    ///
    pub fn new(config: Box<ServerConfig>) -> Server {
        let online_key = OnlineKey::new();
        let public_key: String;

        let cert_bytes = {
            let seed = match kms::load_seed(&config) {
                Ok(seed) => seed,
                Err(e) => {
                    error!("Failed to load seed: {:#?}", e);
                    process::exit(1);
                }
            };
            let mut long_term_key = LongTermKey::new(&seed);
            public_key = hex::encode(long_term_key.public_key());

            long_term_key.make_cert(&online_key).encode().unwrap()
        };

        let keep_running = Arc::new(AtomicBool::new(true));

        let sock_addr = config.udp_socket_addr().expect("udp sock addr");
        let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");

        let poll_duration = Some(Duration::from_millis(100));

        let mut timer: Timer<()> = Timer::default();
        timer.set_timeout(config.status_interval(), ());

        let poll = Poll::new().unwrap();
        poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
            .unwrap();
        poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
            .unwrap();

        let health_listener = if let Some(hc_port) = config.health_check_port() {
            let hc_sock_addr: SocketAddr = format!("{}:{}", config.interface(), hc_port)
                .parse()
                .unwrap();

            let tcp_listener = TcpListener::bind(&hc_sock_addr)
                .expect("failed to bind TCP listener for health check");

            poll.register(&tcp_listener, HEALTH_CHECK, Ready::readable(), PollOpt::edge())
                .unwrap();

            Some(tcp_listener)
        } else {
            None
        };

        let merkle = MerkleTree::new();
        let requests = Vec::with_capacity(config.batch_size() as usize);

        Server {
            config,
            online_key,
            cert_bytes,

            socket,
            health_listener,

            keep_running,
            poll_duration,
            timer,
            poll,
            merkle,
            requests,
            buf: [0u8; 65_536],

            public_key,

            #[cfg(fuzzing)]
            fake_client_socket: UdpSocket::bind(&"127.0.0.1:0".parse().unwrap()).unwrap(),

            stats: PerClientStats::new(),
        }
    }

    /// Returns a reference to the server's long-term public key
    pub fn get_public_key(&self) -> &str {
        &self.public_key
    }

    /// Returns a reference to the server's on-line (delegated) key
    pub fn get_online_key(&self) -> &OnlineKey {
        &self.online_key
    }

    /// Returns a reference to the `ServerConfig` this server was configured with
    pub fn get_config(&self) -> &Box<dyn ServerConfig> {
        &self.config
    }

    /// Returns a reference counted pointer the this server's `keep_running` value.
    pub fn get_keep_running(&self) -> Arc<AtomicBool> {
        self.keep_running.clone()
    }

    #[cfg(fuzzing)]
    pub fn send_to_self(&mut self, data: &[u8]) {
        self.response_counter = 0;
        self.num_bad_requests = 0;
        let res = self
            .fake_client_socket
            .send_to(data, &self.socket.local_addr().unwrap());
        info!("Sent to self: {:?}", res);
    }

    /// The main processing function for incoming connections. This method should be
    /// called repeatedly in a loop to process requests. It returns 'true' when the
    /// server has shutdown (due to keep_running being set to 'false').
    ///
    pub fn process_events(&mut self, events: &mut Events) -> bool {
        self.poll
            .poll(events, self.poll_duration)
            .expect("poll failed");

        for msg in events.iter() {
            match msg.token() {
                MESSAGE => {
                    loop {
                        check_ctrlc!(self.keep_running);

                        self.merkle.reset();
                        self.requests.clear();

                        let socket_now_empty = self.collect_requests();

                        if self.requests.is_empty() {
                            break;
                        }

                        self.send_responses();

                        if socket_now_empty {
                            break;
                        }
                    }
                }

                HEALTH_CHECK => {
                    let listener = self.health_listener.as_ref().unwrap();

                    match listener.accept() {
                        Ok((ref mut stream, src_addr)) => {
                            info!("health check from {}", src_addr);
                            self.stats.add_health_check(&src_addr.ip());

                            match stream.write(HTTP_RESPONSE.as_bytes()) {
                                Ok(_) => (),
                                Err(e) => warn!("error writing health check {}", e),
                            };

                            match stream.shutdown(Shutdown::Both) {
                                Ok(_) => (),
                                Err(e) => warn!("error in health check socket shutdown {}", e),
                            }
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                            debug!("blocking in TCP health check");
                        }
                        Err(e) => {
                            warn!("unexpected health check error {}", e);
                        }
                    }
                }

                STATUS => {
                    for (addr, counts) in self.stats.iter() {
                        info!(
                            "{:16}: {} valid, {} invalid requests; {} responses ({} sent)",
                            format!("{}", addr), counts.valid_requests, counts.invalid_requests,
                            counts.responses_sent,
                            counts.bytes_sent.file_size(fsopts::BINARY).unwrap()
                        );
                    }

                    info!(
                        "Totals: {} unique clients; {} valid, {} invalid requests; {} responses ({} sent)",
                        self.stats.total_unique_clients(),
                        self.stats.total_valid_requests(), self.stats.total_invalid_requests(),
                        self.stats.total_responses_sent(),
                        self.stats.total_bytes_sent().file_size(fsopts::BINARY).unwrap()
                    );

                    self.timer.set_timeout(self.config.status_interval(), ());
                }

                _ => unreachable!(),
            }
        }
        false
    }

    // Read and process client requests from socket until empty or 'batch_size' number of
    // requests have been read.
    fn collect_requests(&mut self) -> bool {
        for i in 0..self.config.batch_size() {
            match self.socket.recv_from(&mut self.buf) {
                Ok((num_bytes, src_addr)) => {
                    match self.nonce_from_request(&self.buf, num_bytes) {
                        Ok(nonce) => {
                            self.stats.add_valid_request(&src_addr.ip());
                            self.requests.push((Vec::from(nonce), src_addr));
                            self.merkle.push_leaf(nonce);
                        }
                        Err(e) => {
                            self.stats.add_invalid_request(&src_addr.ip());

                            info!(
                                "Invalid request: '{:?}' ({} bytes) from {} (#{} in batch, resp #{})",
                                e, num_bytes, src_addr, i,
                                self.stats.total_responses_sent() + u64::from(i)
                            );
                        }
                    }
                }
                Err(e) => match e.kind() {
                    ErrorKind::WouldBlock => {
                        return true;
                    }
                    _ => {
                        error!("Error receiving from socket: {:?}: {:?}", e.kind(), e);
                        return false;
                    }
                },
            };
        }

        false
    }

    // extract the client's nonce from its request
    fn nonce_from_request<'a>(&self, buf: &'a [u8], num_bytes: usize) -> Result<&'a [u8], Error> {
        if num_bytes < MIN_REQUEST_LENGTH as usize {
            return Err(Error::RequestTooShort);
        }

        let tag_count = &buf[..4];
        let expected_nonc = &buf[8..12];
        let expected_pad = &buf[12..16];

        let tag_count_is_2 = tag_count == [0x02, 0x00, 0x00, 0x00];
        let tag1_is_nonc = expected_nonc == Tag::NONC.wire_value();
        let tag2_is_pad = expected_pad == Tag::PAD.wire_value();

        if tag_count_is_2 && tag1_is_nonc && tag2_is_pad {
            Ok(&buf[0x10..0x50])
        } else {
            Err(Error::InvalidRequest)
        }
    }

    fn send_responses(&mut self) -> () {
        let merkle_root = self.merkle.compute_root();

        // The SREP tag is identical for each response
        let srep = self.online_key.make_srep(time::get_time(), &merkle_root);

        for (i, &(ref nonce, ref src_addr)) in self.requests.iter().enumerate() {
            let paths = self.merkle.get_paths(i);
            let resp = self.make_response(&srep, &self.cert_bytes, &paths, i as u32);
            let resp_bytes = resp.encode().unwrap();

            let bytes_sent = self
                .socket
                .send_to(&resp_bytes, &src_addr)
                .expect("send_to failed");

            self.stats.add_response(&src_addr.ip(), bytes_sent);

            info!(
                "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})",
                bytes_sent,
                src_addr,
                hex::encode(&nonce[0..4]),
                i,
                self.stats.total_responses_sent()
            );
        }
    }

    fn make_response(&self, srep: &RtMessage, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage {
        let mut index = [0; 4];
        (&mut index as &mut [u8])
            .write_u32::<LittleEndian>(idx)
            .unwrap();

        let sig_bytes = srep.get_field(Tag::SIG).unwrap();
        let srep_bytes = srep.get_field(Tag::SREP).unwrap();

        let mut response = RtMessage::new(5);
        response.add_field(Tag::SIG, sig_bytes).unwrap();
        response.add_field(Tag::PATH, path).unwrap();
        response.add_field(Tag::SREP, srep_bytes).unwrap();
        response.add_field(Tag::CERT, cert_bytes).unwrap();
        response.add_field(Tag::INDX, &index).unwrap();

        response
    }
}
<commit_msg>Add ServerStats member to the server<commit_after>// Copyright 2017-2019 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! Implements the Roughenough server functionality.
//!

use hex;
use std::io::ErrorKind;
use std::net::SocketAddr;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::io::Write;
use time;

use byteorder::{LittleEndian, WriteBytesExt};

use humansize::{FileSize, file_size_opts as fsopts};

use mio::net::{TcpListener, UdpSocket};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio::tcp::Shutdown;
use mio_extras::timer::Timer;

use crate::{Error, RtMessage, Tag, MIN_REQUEST_LENGTH};
use crate::config::ServerConfig;
use crate::key::{LongTermKey, OnlineKey};
use crate::kms;
use crate::merkle::MerkleTree;
use crate::stats::{AggregatedStats, PerClientStats, ServerStats};

macro_rules! check_ctrlc {
    ($keep_running:expr) => {
        if !$keep_running.load(Ordering::Acquire) {
            warn!("Ctrl-C caught, exiting...");
            return true;
        }
    };
}

// mio event registrations
const MESSAGE: Token = Token(0);
const STATUS: Token = Token(1);
const HEALTH_CHECK: Token = Token(2);

// Canned response to health check request
const HTTP_RESPONSE: &str = "HTTP/1.1 200 OK\nContent-Length: 0\nConnection: close\n\n";

/// The main Roughenough server instance.
///
/// The [ServerConfig](../config/trait.ServerConfig.html) trait specifies the required and optional
/// parameters available for configuring a Roughenoguh server instance.
///
/// Implementations of `ServerConfig` obtain configurations from different back-end sources
/// such as files or environment variables.
///
/// See [the config module](../config/index.html) for more information.
///
pub struct Server {
    config: Box<dyn ServerConfig>,
    online_key: OnlineKey,
    cert_bytes: Vec<u8>,

    socket: UdpSocket,
    health_listener: Option<TcpListener>,
    keep_running: Arc<AtomicBool>,
    poll_duration: Option<Duration>,
    timer: Timer<()>,
    poll: Poll,
    merkle: MerkleTree,
    requests: Vec<(Vec<u8>, SocketAddr)>,
    buf: [u8; 65_536],

    public_key: String,

    stats: Box<dyn ServerStats>,

    // Used to send requests to ourselves in fuzzing mode
    #[cfg(fuzzing)]
    fake_client_socket: UdpSocket,
}

impl Server {
    ///
    /// Create a new server instance from the provided
    /// [`ServerConfig`](../config/trait.ServerConfig.html) trait object instance.
    ///
    pub fn new(config: Box<dyn ServerConfig>) -> Server {
        let online_key = OnlineKey::new();
        let public_key: String;

        let cert_bytes = {
            let seed = match kms::load_seed(&config) {
                Ok(seed) => seed,
                Err(e) => {
                    error!("Failed to load seed: {:#?}", e);
                    process::exit(1);
                }
            };
            let mut long_term_key = LongTermKey::new(&seed);
            public_key = hex::encode(long_term_key.public_key());

            long_term_key.make_cert(&online_key).encode().unwrap()
        };

        let keep_running = Arc::new(AtomicBool::new(true));

        let sock_addr = config.udp_socket_addr().expect("udp sock addr");
        let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");

        let poll_duration = Some(Duration::from_millis(100));

        let mut timer: Timer<()> = Timer::default();
        timer.set_timeout(config.status_interval(), ());

        let poll = Poll::new().unwrap();
        poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
            .unwrap();
        poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
            .unwrap();

        let health_listener = if let Some(hc_port) = config.health_check_port() {
            let hc_sock_addr: SocketAddr = format!("{}:{}", config.interface(), hc_port)
                .parse()
                .unwrap();

            let tcp_listener = TcpListener::bind(&hc_sock_addr)
                .expect("failed to bind TCP listener for health check");

            poll.register(&tcp_listener, HEALTH_CHECK, Ready::readable(), PollOpt::edge())
                .unwrap();

            Some(tcp_listener)
        } else {
            None
        };

        let stats: Box<dyn ServerStats> = if config.client_stats_enabled() {
            Box::new(PerClientStats::new())
        } else {
            Box::new(AggregatedStats::new())
        };

        let merkle = MerkleTree::new();
        let requests = Vec::with_capacity(config.batch_size() as usize);

        Server {
            config,
            online_key,
            cert_bytes,

            socket,
            health_listener,

            keep_running,
            poll_duration,
            timer,
            poll,
            merkle,
            requests,
            buf: [0u8; 65_536],

            public_key,

            stats,

            #[cfg(fuzzing)]
            fake_client_socket: UdpSocket::bind(&"127.0.0.1:0".parse().unwrap()).unwrap(),
        }
    }

    /// Returns a reference to the server's long-term public key
    pub fn get_public_key(&self) -> &str {
        &self.public_key
    }

    /// Returns a reference to the server's on-line (delegated) key
    pub fn get_online_key(&self) -> &OnlineKey {
        &self.online_key
    }

    /// Returns a reference to the `ServerConfig` this server was configured with
    pub fn get_config(&self) -> &Box<dyn ServerConfig> {
        &self.config
    }

    /// Returns a reference counted pointer the this server's `keep_running` value.
    pub fn get_keep_running(&self) -> Arc<AtomicBool> {
        self.keep_running.clone()
    }

    #[cfg(fuzzing)]
    pub fn send_to_self(&mut self, data: &[u8]) {
        self.response_counter = 0;
        self.num_bad_requests = 0;
        let res = self
            .fake_client_socket
            .send_to(data, &self.socket.local_addr().unwrap());
        info!("Sent to self: {:?}", res);
    }

    /// The main processing function for incoming connections. This method should be
    /// called repeatedly in a loop to process requests. It returns 'true' when the
    /// server has shutdown (due to keep_running being set to 'false').
    ///
    pub fn process_events(&mut self, events: &mut Events) -> bool {
        self.poll
            .poll(events, self.poll_duration)
            .expect("poll failed");

        for msg in events.iter() {
            match msg.token() {
                MESSAGE => {
                    loop {
                        check_ctrlc!(self.keep_running);

                        self.merkle.reset();
                        self.requests.clear();

                        let socket_now_empty = self.collect_requests();

                        if self.requests.is_empty() {
                            break;
                        }

                        self.send_responses();

                        if socket_now_empty {
                            break;
                        }
                    }
                }

                HEALTH_CHECK => {
                    let listener = self.health_listener.as_ref().unwrap();

                    match listener.accept() {
                        Ok((ref mut stream, src_addr)) => {
                            info!("health check from {}", src_addr);
                            self.stats.add_health_check(&src_addr.ip());

                            match stream.write(HTTP_RESPONSE.as_bytes()) {
                                Ok(_) => (),
                                Err(e) => warn!("error writing health check {}", e),
                            };

                            match stream.shutdown(Shutdown::Both) {
                                Ok(_) => (),
                                Err(e) => warn!("error in health check socket shutdown {}", e),
                            }
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                            debug!("blocking in TCP health check");
                        }
                        Err(e) => {
                            warn!("unexpected health check error {}", e);
                        }
                    }
                }

                STATUS => {
                    for (addr, counts) in self.stats.iter() {
                        info!(
                            "{:16}: {} valid, {} invalid requests; {} responses ({} sent)",
                            format!("{}", addr), counts.valid_requests, counts.invalid_requests,
                            counts.responses_sent,
                            counts.bytes_sent.file_size(fsopts::BINARY).unwrap()
                        );
                    }

                    info!(
                        "Totals: {} unique clients; {} valid, {} invalid requests; {} responses ({} sent)",
                        self.stats.total_unique_clients(),
                        self.stats.total_valid_requests(), self.stats.total_invalid_requests(),
                        self.stats.total_responses_sent(),
                        self.stats.total_bytes_sent().file_size(fsopts::BINARY).unwrap()
                    );

                    self.timer.set_timeout(self.config.status_interval(), ());
                }

                _ => unreachable!(),
            }
        }
        false
    }

    // Read and process client requests from socket until empty or 'batch_size' number of
    // requests have been read.
    fn collect_requests(&mut self) -> bool {
        for i in 0..self.config.batch_size() {
            match self.socket.recv_from(&mut self.buf) {
                Ok((num_bytes, src_addr)) => {
                    match self.nonce_from_request(&self.buf, num_bytes) {
                        Ok(nonce) => {
                            self.stats.add_valid_request(&src_addr.ip());
                            self.requests.push((Vec::from(nonce), src_addr));
                            self.merkle.push_leaf(nonce);
                        }
                        Err(e) => {
                            self.stats.add_invalid_request(&src_addr.ip());

                            info!(
                                "Invalid request: '{:?}' ({} bytes) from {} (#{} in batch, resp #{})",
                                e, num_bytes, src_addr, i,
                                self.stats.total_responses_sent() + u64::from(i)
                            );
                        }
                    }
                }
                Err(e) => match e.kind() {
                    ErrorKind::WouldBlock => {
                        return true;
                    }
                    _ => {
                        error!("Error receiving from socket: {:?}: {:?}", e.kind(), e);
                        return false;
                    }
                },
            };
        }

        false
    }

    // extract the client's nonce from its request
    fn nonce_from_request<'a>(&self, buf: &'a [u8], num_bytes: usize) -> Result<&'a [u8], Error> {
        if num_bytes < MIN_REQUEST_LENGTH as usize {
            return Err(Error::RequestTooShort);
        }

        let tag_count = &buf[..4];
        let expected_nonc = &buf[8..12];
        let expected_pad = &buf[12..16];

        let tag_count_is_2 = tag_count == [0x02, 0x00, 0x00, 0x00];
        let tag1_is_nonc = expected_nonc == Tag::NONC.wire_value();
        let tag2_is_pad = expected_pad == Tag::PAD.wire_value();

        if tag_count_is_2 && tag1_is_nonc && tag2_is_pad {
            Ok(&buf[0x10..0x50])
        } else {
            Err(Error::InvalidRequest)
        }
    }

    fn send_responses(&mut self) -> () {
        let merkle_root = self.merkle.compute_root();

        // The SREP tag is identical for each response
        let srep = self.online_key.make_srep(time::get_time(), &merkle_root);

        for (i, &(ref nonce, ref src_addr)) in self.requests.iter().enumerate() {
            let paths = self.merkle.get_paths(i);
            let resp = self.make_response(&srep, &self.cert_bytes, &paths, i as u32);
            let resp_bytes = resp.encode().unwrap();

            let bytes_sent = self
                .socket
                .send_to(&resp_bytes, &src_addr)
                .expect("send_to failed");

            self.stats.add_response(&src_addr.ip(), bytes_sent);

            info!(
                "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})",
                bytes_sent,
                src_addr,
                hex::encode(&nonce[0..4]),
                i + 1,
                self.stats.total_responses_sent()
            );
        }
    }

    fn make_response(&self, srep: &RtMessage, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage {
        let mut index = [0; 4];
        (&mut index as &mut [u8])
            .write_u32::<LittleEndian>(idx)
            .unwrap();

        let sig_bytes = srep.get_field(Tag::SIG).unwrap();
        let srep_bytes = srep.get_field(Tag::SREP).unwrap();

        let mut response = RtMessage::new(5);
        response.add_field(Tag::SIG, sig_bytes).unwrap();
        response.add_field(Tag::PATH, path).unwrap();
        response.add_field(Tag::SREP, srep_bytes).unwrap();
        response.add_field(Tag::CERT, cert_bytes).unwrap();
        response.add_field(Tag::INDX, &index).unwrap();

        response
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fmt;
use std::net::{SocketAddr};
use std::io;

use mio::deprecated::{EventLoop, Handler, TryWrite};
use mio::*;
use mio::tcp::*;
use bytes::buf::{Buf, ByteBuf};

use packet::{Packet, EofError};
use queues::QueueHolder;
use worker::Worker;

struct GearmanRemote {
    socket: TcpStream,
    addr: SocketAddr,
    packet: Packet,
    queues: QueueHolder,
    worker: Worker,
    sendqueue: Vec<ByteBuf>,
    interest: Ready,
    token: Token,
}

pub struct GearmanServer {
    pub socket: TcpListener,
    remotes: HashMap<Token, GearmanRemote>,
    token_counter: usize,
    queues: QueueHolder,
}

const SERVER_TOKEN: Token = Token(0);

impl GearmanRemote {
    pub fn new(socket: TcpStream, addr: SocketAddr, queues: QueueHolder, token: Token) -> GearmanRemote {
        GearmanRemote {
            socket: socket,
            addr: addr,
            packet: Packet::new(token),
            queues: queues,
            worker: Worker::new(),
            sendqueue: Vec::with_capacity(2), // Don't need many bufs
            interest: Ready::readable(),
            token: token,
        }
    }

    pub fn queue_packet(&mut self, packet: &Packet) {
        info!("{} Queueing {:?}", self, &packet);
        self.sendqueue.push(ByteBuf::from_slice(&packet.to_byteslice()));
        self.interest.remove(Ready::readable());
        self.interest.insert(Ready::writable());
    }

    pub fn read(&mut self) -> Result<Option<Packet>, EofError> {
        let mut ret = Ok(None);
        match self.packet.from_socket(&mut self.socket, &mut self.worker, self.queues.clone(), self.token)? {
            None => debug!("{} Done reading", self),
            Some(p) => {
                ret = Ok(Some(p));
            }
        }
        // Packet is consumed, reset
        self.packet = Packet::new(self.token);
        ret
    }

    pub fn write(&mut self) -> Result<(), io::Error> {
        while !self.sendqueue.is_empty() {
            if !self.sendqueue.first().unwrap().has_remaining() {
                self.sendqueue.pop();
                continue;
            }
            let buf = self.sendqueue.first_mut().unwrap();
            match self.socket.try_write(buf.bytes())? {
                None => break,
                Some(n) => {
                    buf.advance(n);
                    continue
                }
            };
        }
        if self.sendqueue.is_empty() {
            self.interest.remove(Ready::writable());
            self.interest.insert(Ready::readable());
        };
        Ok(())
    }

    pub fn shutdown(self) {
        match self.worker.job {
            Some(j) => {
                self.queues.clone().add_job(j)
            },
            None => {},
        }
        self.socket.shutdown(Shutdown::Both).unwrap();
    }
}

impl fmt::Display for GearmanRemote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Remote {{ addr: {:?} }}", self.addr)
    }
}

impl GearmanServer {
    pub fn new(server_socket: TcpListener, queues: QueueHolder) -> GearmanServer {
        GearmanServer {
            token_counter: 1,
            remotes: HashMap::new(),
            socket: server_socket,
            queues: queues,
        }
    }

}

impl Handler for GearmanServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<GearmanServer>,
             token: Token, events: Ready)
    {
        if events.is_readable() {
            match token {
                SERVER_TOKEN => {
                    let (remote_socket, remote_addr) = match self.socket.accept() {
                        Err(e) => {
                            error!("Accept error: {}", e);
                            return;
                        },
                        Ok((sock, addr)) => (sock, addr),
                    };

                    self.token_counter += 1;
                    let new_token = Token(self.token_counter);

                    self.remotes.insert(new_token, GearmanRemote::new(remote_socket, remote_addr, self.queues.clone(), new_token));

                    event_loop.register(&self.remotes[&new_token].socket,
                                        new_token, Ready::readable(),
                                        PollOpt::edge() | PollOpt::oneshot()).unwrap();
                },
                token => {
                    let mut shutdown = false;
                    {
                        let mut other_packet = None;
                        {
                            let mut remote = self.remotes.get_mut(&token).unwrap();
                            match remote.read() {
                                Ok(sp) => {
                                    match sp {
                                        Some(p) => {
                                            match p.remote {
                                                None => remote.queue_packet(&p), // Packet is for us
                                                Some(t) => {
                                                    if t == token {
                                                        // Packet is also meant for us
                                                        remote.queue_packet(&p);
                                                    } else {
                                                        // Packet is for a different remote
                                                        other_packet = Some(p);
                                                    }
                                                },
                                            };
                                        },
                                        None => {},
                                    }
                                    event_loop.reregister(&remote.socket, token, remote.interest,
                                                      PollOpt::edge() | PollOpt::oneshot()).unwrap();
                                },
                                Err(e) => {
                                    info!("remote({}) hung up: {:?}", &remote, e);
                                    shutdown = true;
                                }
                            }
                        }
                        match other_packet {
                            None => {},
                            Some(p) => {
                                let t = p.remote.unwrap();
                                let mut remote = self.remotes.get_mut(&t).unwrap(); // XXX
                                remote.queue_packet(&p);
                                event_loop.reregister(&remote.socket, t, remote.interest,
                                                      PollOpt::edge() | PollOpt::oneshot()).unwrap();
                            },
                        }
                    }
                    if shutdown {
                        let remote = self.remotes.remove(&token).unwrap();
                        remote.shutdown();
                    }
                },
            }
        }

        if events.is_writable() {
            match token {
                SERVER_TOKEN => panic!("Received writable event for server socket."),
                token => {
                    let mut shutdown = false;
                    {
                        let mut remote = self.remotes.get_mut(&token).unwrap();
                        match remote.write() {
                            Ok(_) => event_loop.reregister(&remote.socket, token, remote.interest,
                                                          PollOpt::edge() | PollOpt::oneshot()).unwrap(),
                            Err(e) => {
                                info!("remote({}) hung up: {}", &remote, e);
                                shutdown = true;
                            }
                        }
                    }
                    if shutdown {
                        let remote = self.remotes.remove(&token).unwrap();
                        remote.shutdown();
                    }
                },
            }
        }
    }
}
<commit_msg>Handle remote that goes missing<commit_after>use std::collections::HashMap;
use std::fmt;
use std::net::{SocketAddr};
use std::io;

use mio::deprecated::{EventLoop, Handler, TryWrite};
use mio::*;
use mio::tcp::*;
use bytes::buf::{Buf, ByteBuf};

use packet::{Packet, EofError};
use queues::QueueHolder;
use worker::Worker;

struct GearmanRemote {
    socket: TcpStream,
    addr: SocketAddr,
    packet: Packet,
    queues: QueueHolder,
    worker: Worker,
    sendqueue: Vec<ByteBuf>,
    interest: Ready,
    token: Token,
}

pub struct GearmanServer {
    pub socket: TcpListener,
    remotes: HashMap<Token, GearmanRemote>,
    token_counter: usize,
    queues: QueueHolder,
}

const SERVER_TOKEN: Token = Token(0);

impl GearmanRemote {
    pub fn new(socket: TcpStream, addr: SocketAddr, queues: QueueHolder, token: Token) -> GearmanRemote {
        GearmanRemote {
            socket: socket,
            addr: addr,
            packet: Packet::new(token),
            queues: queues,
            worker: Worker::new(),
            sendqueue: Vec::with_capacity(2), // Don't need many bufs
            interest: Ready::readable(),
            token: token,
        }
    }

    pub fn queue_packet(&mut self, packet: &Packet) {
        info!("{} Queueing {:?}", self, &packet);
        self.sendqueue.push(ByteBuf::from_slice(&packet.to_byteslice()));
        self.interest.remove(Ready::readable());
        self.interest.insert(Ready::writable());
    }

    pub fn read(&mut self) -> Result<Option<Packet>, EofError> {
        let mut ret = Ok(None);
        match self.packet.from_socket(&mut self.socket, &mut self.worker, self.queues.clone(), self.token)? {
            None => debug!("{} Done reading", self),
            Some(p) => {
                ret = Ok(Some(p));
            }
        }
        // Packet is consumed, reset
        self.packet = Packet::new(self.token);
        ret
    }

    pub fn write(&mut self) -> Result<(), io::Error> {
        while !self.sendqueue.is_empty() {
            if !self.sendqueue.first().unwrap().has_remaining() {
                self.sendqueue.pop();
                continue;
            }
            let buf = self.sendqueue.first_mut().unwrap();
            match self.socket.try_write(buf.bytes())? {
                None => break,
                Some(n) => {
                    buf.advance(n);
                    continue
                }
            };
        }
        if self.sendqueue.is_empty() {
            self.interest.remove(Ready::writable());
            self.interest.insert(Ready::readable());
        };
        Ok(())
    }

    pub fn shutdown(self) {
        match self.worker.job {
            Some(j) => {
                self.queues.clone().add_job(j)
            },
            None => {},
        }
        self.socket.shutdown(Shutdown::Both).unwrap();
    }
}

impl fmt::Display for GearmanRemote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Remote {{ addr: {:?} }}", self.addr)
    }
}

impl GearmanServer {
    pub fn new(server_socket: TcpListener, queues: QueueHolder) -> GearmanServer {
        GearmanServer {
            token_counter: 1,
            remotes: HashMap::new(),
            socket: server_socket,
            queues: queues,
        }
    }

}

impl Handler for GearmanServer {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<GearmanServer>,
             token: Token, events: Ready)
    {
        if events.is_readable() {
            match token {
                SERVER_TOKEN => {
                    let (remote_socket, remote_addr) = match self.socket.accept() {
                        Err(e) => {
                            error!("Accept error: {}", e);
                            return;
                        },
                        Ok((sock, addr)) => (sock, addr),
                    };

                    self.token_counter += 1;
                    let new_token = Token(self.token_counter);

                    self.remotes.insert(new_token, GearmanRemote::new(remote_socket, remote_addr, self.queues.clone(), new_token));

                    event_loop.register(&self.remotes[&new_token].socket,
                                        new_token, Ready::readable(),
                                        PollOpt::edge() | PollOpt::oneshot()).unwrap();
                },
                token => {
                    let mut shutdown = false;
                    {
                        let mut other_packet = None;
                        {
                            let mut remote = self.remotes.get_mut(&token).unwrap();
                            match remote.read() {
                                Ok(sp) => {
                                    match sp {
                                        Some(p) => {
                                            match p.remote {
                                                None => remote.queue_packet(&p), // Packet is for us
                                                Some(t) => {
                                                    if t == token {
                                                        // Packet is also meant for us
                                                        remote.queue_packet(&p);
                                                    } else {
                                                        // Packet is for a different remote
                                                        other_packet = Some(p);
                                                    }
                                                },
                                            };
                                        },
                                        None => {},
                                    }
                                    event_loop.reregister(&remote.socket, token, remote.interest,
                                                      PollOpt::edge() | PollOpt::oneshot()).unwrap();
                                },
                                Err(e) => {
                                    info!("remote({}) hung up: {:?}", &remote, e);
                                    shutdown = true;
                                }
                            }
                        }
                        match other_packet {
                            None => {},
                            Some(p) => {
                                let t = p.remote.unwrap();
                                match self.remotes.get_mut(&t) {
                                    None => warn!("No remote for packet, dropping: {:?}", &p),
                                    Some(mut remote) => {
                                        remote.queue_packet(&p);
                                        event_loop.reregister(&remote.socket, t, remote.interest,
                                                              PollOpt::edge() | PollOpt::oneshot()).unwrap();
                                    },
                                }
                            },
                        }
                    }
                    if shutdown {
                        let remote = self.remotes.remove(&token).unwrap();
                        remote.shutdown();
                    }
                },
            }
        }

        if events.is_writable() {
            match token {
                SERVER_TOKEN => panic!("Received writable event for server socket."),
                token => {
                    let mut shutdown = false;
                    {
                        let mut remote = self.remotes.get_mut(&token).unwrap();
                        match remote.write() {
                            Ok(_) => event_loop.reregister(&remote.socket, token, remote.interest,
                                                          PollOpt::edge() | PollOpt::oneshot()).unwrap(),
                            Err(e) => {
                                info!("remote({}) hung up: {}", &remote, e);
                                shutdown = true;
                            }
                        }
                    }
                    if shutdown {
                        let remote = self.remotes.remove(&token).unwrap();
                        remote.shutdown();
                    }
                },
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::Sender;

use message::Message;
use roommap::{Room, RoomMap};
use usermap::UserMap;

pub struct Server {
    users: UserMap,
    rooms: RoomMap,
}

impl Server {
    pub fn new() -> Self {
        Server {
            users: UserMap::new(),
            rooms: RoomMap::new(),
        }
    }

    pub fn welcome_user(stream: TcpStream) {
        let mut stream = stream;
        let welcome_msg = "Welcome to Smazy\nPlease enter a username:\n".to_string();
        stream.write(&welcome_msg.into_bytes()).expect("Error writing to stream");
    }

    /// Add user to server
    /// Fails if a user with the same name already exists
    /// Return boolean indicating success/failure
    pub fn add_user(&mut self, name: String) -> bool {
        if !self.users.contains_key(&name) {
            self.users.insert(name, 0);
            return true;
        }
        return false;
    }

    /// Send message to all users in the room that the sender is in
    pub fn send_message(&self, msg: Message) {
        if let Some(room) = self.rooms.get(&msg.room_id()) {
            let members = room.members();
            let output = msg.from().to_string() + ": " + msg.content() + "\n";
            for (name, sndr) in members {
                if name != msg.from() {
                    sndr.send(output.to_string()).unwrap();
                }
            }
        }
    }

    /// Add a user to a chatroom
    /// Fails if room_id is invalid
    /// Return boolean indicating success/failure
    pub fn join_room(&mut self, room_id: usize, user: String, sndr: Sender<String>) -> bool {
        let mut valid = false;
        if let Some(room) = self.rooms.get_mut(&room_id) {
            room.add_member(user.to_string(), sndr);
            valid = true;
        }
        if valid {
            let room_name  = &self.rooms.get(&room_id).unwrap().name();
            let join_msg = user.to_string() + " has joined " + room_name;
            let msg = Message::new("Server".to_string(),
                                   room_id,
                                   join_msg);
            self.send_message(msg);
        }
        valid
    }

    /// Create a new chatroom
    /// Return room_id
    pub fn create_room(&mut self, room_name: String) -> usize {
        let room_id = self.rooms.len() + 1;
        self.rooms.insert(room_id, Room::new(room_name));
        room_id
    }

    /// Remove a user from a chatroom
    pub fn leave_room(&mut self, room_id: usize, user: String) {
        if let Some(room) = self.rooms.get_mut(&room_id) {
            room.remove_member(user);
        }
    }

    /// Write a list of the available chatrooms to a stream
    pub fn display_rooms(&self, stream: TcpStream) {
        let mut stream = stream;
        for (room_id, room) in &self.rooms {
            write!(stream, "{}: {}", room_id, room.name()).unwrap();
        }
    }
}<commit_msg>Cleaner join_room<commit_after>use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::Sender;

use message::Message;
use roommap::{Room, RoomMap};
use usermap::UserMap;

pub struct Server {
    users: UserMap,
    rooms: RoomMap,
}

impl Server {
    pub fn new() -> Self {
        Server {
            users: UserMap::new(),
            rooms: RoomMap::new(),
        }
    }

    pub fn welcome_user(stream: TcpStream) {
        let mut stream = stream;
        let welcome_msg = "Welcome to Smazy\nPlease enter a username:\n".to_string();
        stream.write(&welcome_msg.into_bytes()).expect("Error writing to stream");
    }

    /// Add user to server
    /// Fails if a user with the same name already exists
    /// Return boolean indicating success/failure
    pub fn add_user(&mut self, name: String) -> bool {
        if !self.users.contains_key(&name) {
            self.users.insert(name, 0);
            return true;
        }
        return false;
    }

    /// Send message to all users in the room that the sender is in
    pub fn send_message(&self, msg: Message) {
        if let Some(room) = self.rooms.get(&msg.room_id()) {
            let members = room.members();
            let output = msg.from().to_string() + ": " + msg.content() + "\n";
            for (name, sndr) in members {
                if name != msg.from() {
                    sndr.send(output.to_string()).unwrap();
                }
            }
        }
    }

    /// Add a user to a chatroom
    /// Fails if room_id is invalid
    /// Return boolean indicating success/failure
    pub fn join_room(&mut self, room_id: usize, user: String, sndr: Sender<String>) -> bool {
        if !self.rooms.contains_key(&room_id) {
            return false;
        }
        self.rooms.get_mut(&room_id).unwrap().add_member(user.to_string(), sndr);
        let room_name  = &self.rooms.get(&room_id).unwrap().name();
        let join_msg = user.to_string() + " has joined " + room_name;
        let msg = Message::new("Server".to_string(), room_id, join_msg);
        self.send_message(msg);
        true
    }

    /// Create a new chatroom
    /// Return room_id
    pub fn create_room(&mut self, room_name: String) -> usize {
        let room_id = self.rooms.len() + 1;
        self.rooms.insert(room_id, Room::new(room_name));
        room_id
    }

    /// Remove a user from a chatroom
    pub fn leave_room(&mut self, room_id: usize, user: String) {
        if let Some(room) = self.rooms.get_mut(&room_id) {
            room.remove_member(user);
        }
    }

    /// Write a list of the available chatrooms to a stream
    pub fn display_rooms(&self, stream: TcpStream) {
        let mut stream = stream;
        for (room_id, room) in &self.rooms {
            write!(stream, "{}: {}", room_id, room.name()).unwrap();
        }
    }
}<|endoftext|>


<commit_before>// Implement repeating-key XOR
// Here is the opening stanza of an important work of the English language:

// Burning 'em, if you ain't quick and nimble
// I go crazy when I hear a cymbal
// Encrypt it, under the key "ICE", using repeating-key XOR.

// In repeating-key XOR, you'll sequentially apply each byte of the key;
// the first byte of plaintext will be XOR'd against I, the next C,
// the next E, then I again for the 4th byte, and so on.

// It should come out to:

// 0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272
// a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f

// Encrypt a bunch of stuff using your repeating-key XOR function.
// Encrypt your mail. Encrypt your password file. Your .sig file.
// Get a feel for it. I promise, we aren't wasting your time with this.

#![feature(core)]

#[macro_use]
extern crate log;

use std::str;

#[cfg(not(test))]
fn main() {
	let input = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal";
	let key = "ICE";
	println!("input: {:?}, key: {:?}", input, key);
	let output = encrypt_repeating_byte_xor(input, key);
	println!("output: {:?}", output);
}

fn encrypt_repeating_byte_xor(input: &str, key: &str) -> String {
	let mut output: Vec<u8> = vec!();
	let input_iter = input.bytes();
	let mut key_iter = key.bytes().cycle();
	for byte in input_iter {
		output.push(byte ^ key_iter.next().unwrap());
	}
	convert_decimals_to_hex_string( output )
}

fn convert_decimals_to_hex_string(decimals: Vec<u8>) -> String {
	let mut converted_string: Vec<u8> = vec!();
	for num in decimals {
		if num < 16 {
			converted_string.push(convert_decimal_to_hex_char(0));
			converted_string.push(convert_decimal_to_hex_char(num));
		} else {
			converted_string.push(convert_decimal_to_hex_char(num / 16));
			converted_string.push(convert_decimal_to_hex_char(num % 16));
		}
	}

	// turn the byte vector into a string
	match str::from_utf8(converted_string.as_slice()) {
	    Ok(v) => {
	        return v.to_string();
	    }
	    Err(_) => { panic!("Error converting numbers to string") }
	}
}

fn convert_decimal_to_hex_char(decimal: u8) -> u8 {
	match decimal {
		0...9 => decimal + 48,
		10...15 => decimal + 87,
		_ => panic!("Not a valid hex char")
	}
}

#[cfg(test)]
mod set1challenge5 {

	#[test]
	fn challenge() {
		let output = super::encrypt_repeating_byte_xor("Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal", "ICE");
		assert_eq!(output, "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f".to_string());
	}

	#[test]
	fn wizard() {
		let output = super::encrypt_repeating_byte_xor("I like the wizard of oz", "TEST");
		assert_eq!(output, "1d653f3d3f2073203c2073233d3f322630653c32742a29".to_string());
	}

}
<commit_msg>Update challenge 5 to latest Rust<commit_after>// Implement repeating-key XOR
// Here is the opening stanza of an important work of the English language:

// Burning 'em, if you ain't quick and nimble
// I go crazy when I hear a cymbal
// Encrypt it, under the key "ICE", using repeating-key XOR.

// In repeating-key XOR, you'll sequentially apply each byte of the key;
// the first byte of plaintext will be XOR'd against I, the next C,
// the next E, then I again for the 4th byte, and so on.

// It should come out to:

// 0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272
// a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f

// Encrypt a bunch of stuff using your repeating-key XOR function.
// Encrypt your mail. Encrypt your password file. Your .sig file.
// Get a feel for it. I promise, we aren't wasting your time with this.

#[macro_use]
extern crate log;

use std::str;

#[cfg(not(test))]
fn main() {
	let input = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal";
	let key = "ICE";
	println!("input: {:?}, key: {:?}", input, key);
	let output = encrypt_repeating_byte_xor(input, key);
	println!("output: {:?}", output);
}

fn encrypt_repeating_byte_xor(input: &str, key: &str) -> String {
	let mut output: Vec<u8> = vec!();
	let input_iter = input.bytes();
	let mut key_iter = key.bytes().cycle();
	for byte in input_iter {
		output.push(byte ^ key_iter.next().unwrap());
	}
	convert_decimals_to_hex_string( output )
}

fn convert_decimals_to_hex_string(decimals: Vec<u8>) -> String {
	let mut converted_string: Vec<u8> = vec!();
	for num in decimals {
		if num < 16 {
			converted_string.push(convert_decimal_to_hex_char(0));
			converted_string.push(convert_decimal_to_hex_char(num));
		} else {
			converted_string.push(convert_decimal_to_hex_char(num / 16));
			converted_string.push(convert_decimal_to_hex_char(num % 16));
		}
	}

	// turn the byte vector into a string
	match str::from_utf8(&converted_string) {
	    Ok(v) => {
	        return v.to_string();
	    }
	    Err(_) => { panic!("Error converting numbers to string") }
	}
}

fn convert_decimal_to_hex_char(decimal: u8) -> u8 {
	match decimal {
		0...9 => decimal + 48,
		10...15 => decimal + 87,
		_ => panic!("Not a valid hex char")
	}
}

#[cfg(test)]
mod set1challenge5 {

	#[test]
	fn challenge() {
		let output = super::encrypt_repeating_byte_xor("Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal", "ICE");
		assert_eq!(output, "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f".to_string());
	}

	#[test]
	fn wizard() {
		let output = super::encrypt_repeating_byte_xor("I like the wizard of oz", "TEST");
		assert_eq!(output, "1d653f3d3f2073203c2073233d3f322630653c32742a29".to_string());
	}

}
<|endoftext|>


<commit_before>use super::{layout, types, ids, development};

pub trait UiApplication {
    fn new_window(&mut self, title: &str, size: types::WindowStartSize, has_menu: bool) -> Box<UiWindow>;
    fn name(&self) -> &str;
    fn start(&mut self);
}

pub trait UiMember {
    fn size(&self) -> (u16, u16);
    fn on_resize(&mut self, Option<Box<FnMut(&mut UiMember, u16, u16)>>);

    fn set_visibility(&mut self, visibility: types::Visibility);
    fn visibility(&self) -> types::Visibility;
	fn id(&self) -> ids::Id;

    unsafe fn native_id(&self) -> usize;

    fn member_id(&self) -> &'static str;
    fn is_control(&self) -> Option<&UiControl>;
    fn is_control_mut(&mut self) -> Option<&mut UiControl>;
}

pub trait UiLayedOut: UiMember {
	fn layout_width(&self) -> layout::Size;
	fn layout_height(&self) -> layout::Size;
	fn layout_gravity(&self) -> layout::Gravity;
	fn layout_orientation(&self) -> layout::Orientation;
	fn layout_alignment(&self) -> layout::Alignment;

	fn set_layout_width(&mut self, layout::Size);
	fn set_layout_height(&mut self, layout::Size);
	fn set_layout_gravity(&mut self, layout::Gravity);
	fn set_layout_orientation(&mut self, layout::Orientation);
	fn set_layout_alignment(&mut self, layout::Alignment);
}

pub trait UiControl: UiLayedOut + development::UiDrawable {
    fn is_container_mut(&mut self) -> Option<&mut UiContainer>;
    fn is_container(&self) -> Option<&UiContainer>;

	fn on_added_to_container(&mut self, &UiContainer, x: u16, y: u16);
    fn on_removed_from_container(&mut self, &UiContainer);

    fn parent(&self) -> Option<&types::UiMemberCommon>;
    fn parent_mut(&mut self) -> Option<&mut types::UiMemberCommon>;
    fn root(&self) -> Option<&types::UiMemberCommon>;
    fn root_mut(&mut self) -> Option<&mut types::UiMemberCommon>;

    #[cfg(feature = "markup")]
    fn fill_from_markup(&mut self, &super::markup::Markup, &mut super::markup::MarkupRegistry);
}

pub trait UiContainer: UiMember {
    fn find_control_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiControl>;
    fn find_control_by_id(&self, id: ids::Id) -> Option<&UiControl>;

    fn is_multi_mut(&mut self) -> Option<&mut UiMultiContainer> { None }
    fn is_multi(&self) -> Option<&UiMultiContainer> { None }
    fn is_single_mut(&mut self) -> Option<&mut UiSingleContainer> { None }
    fn is_single(&self) -> Option<&UiSingleContainer> { None }
}

pub trait UiSingleContainer: UiContainer {
	fn set_child(&mut self, Option<Box<UiControl>>) -> Option<Box<UiControl>>;
    fn child(&self) -> Option<&UiControl>;
    fn child_mut(&mut self) -> Option<&mut UiControl>;
}

pub trait UiMultiContainer: UiContainer {
    fn len(&self) -> usize;
    fn set_child_to(&mut self, index: usize, Box<UiControl>) -> Option<Box<UiControl>>;
    fn remove_child_from(&mut self, index: usize) -> Option<Box<UiControl>>;
    fn child_at(&self, index: usize) -> Option<&Box<UiControl>>;
    fn child_at_mut(&mut self, index: usize) -> Option<&mut Box<UiControl>>;

    fn clear(&mut self) {
        let len = self.len();
        for index in (0..len).rev() {
            self.remove_child_from(index);
        }
    }
    fn push_child(&mut self, child: Box<UiControl>) {
        let len = self.len();
        self.set_child_to(len, child);
    }
    fn pop_child(&mut self) -> Option<Box<UiControl>> {
        let len = self.len();
        if len > 0 {
        	self.remove_child_from(len - 1)
        } else {
        	None
        }
    }
}

pub trait UiWindow: UiSingleContainer {}

pub trait UiButton: UiControl {
    //fn new(label: &str) -> Box<Self>;
    fn label(&self) -> &str;
    fn set_label(&mut self, &str);
    fn on_left_click(&mut self, Option<Box<FnMut(&mut UiButton)>>);
}

pub trait UiLinearLayout: UiMultiContainer + UiControl {
    fn orientation(&self) -> layout::Orientation;
    fn set_orientation(&mut self, layout::Orientation);
}

pub trait UiRelativeLayout: UiMultiContainer + UiControl {}<commit_msg>Trait nesting<commit_after>use super::{layout, types, ids, development};

pub trait UiApplication {
    fn new_window(&mut self, title: &str, size: types::WindowStartSize, has_menu: bool) -> Box<UiWindow>;
    fn name(&self) -> &str;
    fn start(&mut self);
    fn find_member_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiMember>;
    fn find_member_by_id(&self, id: ids::Id) -> Option<&UiMember>;
}

pub trait UiMember {
    fn size(&self) -> (u16, u16);
    fn on_resize(&mut self, Option<Box<FnMut(&mut UiMember, u16, u16)>>);

    fn set_visibility(&mut self, visibility: types::Visibility);
    fn visibility(&self) -> types::Visibility;
	fn id(&self) -> ids::Id;

    unsafe fn native_id(&self) -> usize;

    fn member_id(&self) -> &'static str;
    fn is_control(&self) -> Option<&UiControl>;
    fn is_control_mut(&mut self) -> Option<&mut UiControl>;
}

pub trait UiLayedOut: UiMember {
	fn layout_width(&self) -> layout::Size;
	fn layout_height(&self) -> layout::Size;
	fn layout_gravity(&self) -> layout::Gravity;
	fn layout_orientation(&self) -> layout::Orientation;
	fn layout_alignment(&self) -> layout::Alignment;

	fn set_layout_width(&mut self, layout::Size);
	fn set_layout_height(&mut self, layout::Size);
	fn set_layout_gravity(&mut self, layout::Gravity);
	fn set_layout_orientation(&mut self, layout::Orientation);
	fn set_layout_alignment(&mut self, layout::Alignment);

	fn as_member(&self) -> &UiMember;
	fn as_member_mut(&mut self) -> &mut UiMember;
}

pub trait UiControl: UiLayedOut + development::UiDrawable {
    fn is_container_mut(&mut self) -> Option<&mut UiContainer>;
    fn is_container(&self) -> Option<&UiContainer>;

	fn on_added_to_container(&mut self, &UiContainer, x: u16, y: u16);
    fn on_removed_from_container(&mut self, &UiContainer);

    fn parent(&self) -> Option<&types::UiMemberCommon>;
    fn parent_mut(&mut self) -> Option<&mut types::UiMemberCommon>;
    fn root(&self) -> Option<&types::UiMemberCommon>;
    fn root_mut(&mut self) -> Option<&mut types::UiMemberCommon>;

	fn as_layed_out(&self) -> &UiLayedOut;
	fn as_layed_out_mut(&mut self) -> &mut UiLayedOut;

    #[cfg(feature = "markup")]
    fn fill_from_markup(&mut self, &super::markup::Markup, &mut super::markup::MarkupRegistry);
}

pub trait UiContainer: UiMember {
    fn find_control_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiControl>;
    fn find_control_by_id(&self, id: ids::Id) -> Option<&UiControl>;

    fn is_multi_mut(&mut self) -> Option<&mut UiMultiContainer> { None }
    fn is_multi(&self) -> Option<&UiMultiContainer> { None }
    fn is_single_mut(&mut self) -> Option<&mut UiSingleContainer> { None }
    fn is_single(&self) -> Option<&UiSingleContainer> { None }

	fn as_member(&self) -> &UiMember;
	fn as_member_mut(&mut self) -> &mut UiMember;
}

pub trait UiSingleContainer: UiContainer {
	fn set_child(&mut self, Option<Box<UiControl>>) -> Option<Box<UiControl>>;
    fn child(&self) -> Option<&UiControl>;
    fn child_mut(&mut self) -> Option<&mut UiControl>;

	fn as_container(&self) -> &UiContainer;
	fn as_container_mut(&mut self) -> &mut UiContainer;
}

pub trait UiMultiContainer: UiContainer {
    fn len(&self) -> usize;
    fn set_child_to(&mut self, index: usize, Box<UiControl>) -> Option<Box<UiControl>>;
    fn remove_child_from(&mut self, index: usize) -> Option<Box<UiControl>>;
    fn child_at(&self, index: usize) -> Option<&Box<UiControl>>;
    fn child_at_mut(&mut self, index: usize) -> Option<&mut Box<UiControl>>;

	fn as_container(&self) -> &UiContainer;
	fn as_container_mut(&mut self) -> &mut UiContainer;

    fn clear(&mut self) {
        let len = self.len();
        for index in (0..len).rev() {
            self.remove_child_from(index);
        }
    }
    fn push_child(&mut self, child: Box<UiControl>) {
        let len = self.len();
        self.set_child_to(len, child);
    }
    fn pop_child(&mut self) -> Option<Box<UiControl>> {
        let len = self.len();
        if len > 0 {
        	self.remove_child_from(len - 1)
        } else {
        	None
        }
    }
}

pub trait UiWindow: UiSingleContainer {
	fn as_single_container(&self) -> &UiSingleContainer;
	fn as_single_container_mut(&mut self) -> &mut UiSingleContainer;
}

pub trait UiButton: UiControl {
    //fn new(label: &str) -> Box<Self>;
    fn label(&self) -> &str;
    fn set_label(&mut self, &str);
    fn on_left_click(&mut self, Option<Box<FnMut(&mut UiButton)>>);

	fn as_control(&self) -> &UiControl;
	fn as_control_mut(&mut self) -> &mut UiControl;
}

pub trait UiLinearLayout: UiMultiContainer + UiControl {
    fn orientation(&self) -> layout::Orientation;
    fn set_orientation(&mut self, layout::Orientation);

	fn as_control(&self) -> &UiControl;
	fn as_control_mut(&mut self) -> &mut UiControl;
	fn as_multi_container(&self) -> &UiMultiContainer;
	fn as_multi_container_mut(&mut self) -> &mut UiMultiContainer;
}

pub trait UiRelativeLayout: UiMultiContainer + UiControl {}<|endoftext|>


<commit_before>use enums::Direction;
use structs::Point;
use traits::HasValues;

/// Create a point in the specified direction a specified number of units
///
/// # Example
///
/// ```
/// use hex_math::{Direction, Point, travel};
///
/// let point: Point = Point::new(1, 2, 5);
///
/// assert_eq!(travel(&point, &Direction::East     , 2), Point::new( 3, 2, 5));
/// assert_eq!(travel(&point, &Direction::Southeast, 2), Point::new( 1, 4, 5));
/// assert_eq!(travel(&point, &Direction::Southwest, 2), Point::new(-1, 4, 5));
/// assert_eq!(travel(&point, &Direction::West     , 2), Point::new(-1, 2, 5));
/// assert_eq!(travel(&point, &Direction::Northwest, 2), Point::new( 1, 0, 5));
/// assert_eq!(travel(&point, &Direction::Northeast, 2), Point::new( 3, 0, 5));
/// assert_eq!(travel(&point, &Direction::Up       , 2), Point::new( 1, 2, 7));
/// assert_eq!(travel(&point, &Direction::Down     , 2), Point::new( 1, 2, 3));
/// ```
pub fn travel<T: HasValues>(
  point: &T,
  direction: &Direction,
  units: i32
) -> Point {
  let (q, r, t) = point.values();

  return match direction {
    &Direction::East      => Point::new(q + units, r        , t        ),
    &Direction::Southeast => Point::new(q        , r + units, t        ),
    &Direction::Southwest => Point::new(q - units, r + units, t        ),
    &Direction::West      => Point::new(q - units, r        , t        ),
    &Direction::Northwest => Point::new(q        , r - units, t        ),
    &Direction::Northeast => Point::new(q + units, r - units, t        ),
    &Direction::Up        => Point::new(q        , r        , t + units),
    &Direction::Down      => Point::new(q        , r        , t - units),
  }

}
<commit_msg>Issue #33: Refactor travel<commit_after>use enums::Direction;
use enums::Direction::*;
use structs::Point;
use traits::HasValues;

/// Create a point in the specified direction a specified number of units
pub fn travel<T: HasValues>(
  point: &T,
  direction: &Direction,
  units: i32
) -> Point {
  let (q, r, t) = point.values();

  return match direction {
    &East      => Point::new(q + units, r        , t        ),
    &Southeast => Point::new(q        , r + units, t        ),
    &Southwest => Point::new(q - units, r + units, t        ),
    &West      => Point::new(q - units, r        , t        ),
    &Northwest => Point::new(q        , r - units, t        ),
    &Northeast => Point::new(q + units, r - units, t        ),
    &Up        => Point::new(q        , r        , t + units),
    &Down      => Point::new(q        , r        , t - units),
  }

}

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

  #[test]
  fn travel() {
    let point: Point = Point::new(1, 2, 5);

    assert!(Point::new( 3, 2, 5) == super::travel(&point, &East     , 2));
    assert!(Point::new( 1, 4, 5) == super::travel(&point, &Southeast, 2));
    assert!(Point::new(-1, 4, 5) == super::travel(&point, &Southwest, 2));
    assert!(Point::new(-1, 2, 5) == super::travel(&point, &West     , 2));
    assert!(Point::new( 1, 0, 5) == super::travel(&point, &Northwest, 2));
    assert!(Point::new( 3, 0, 5) == super::travel(&point, &Northeast, 2));
    assert!(Point::new( 1, 2, 7) == super::travel(&point, &Up       , 2));
    assert!(Point::new( 1, 2, 3) == super::travel(&point, &Down     , 2));
  }

}
<|endoftext|>


<commit_before>use super::{Color, Event, Rect, Renderer};

use std::any::Any;
use std::cell::Cell;

pub struct WidgetCore {
    pub rect: Cell<Rect>,
    pub bg: Color,
    pub fg: Color,
}

impl WidgetCore {
    pub fn new(bg: Color, fg: Color) -> Self {
        WidgetCore {
            rect: Cell::new(Rect::default()),
            bg: bg,
            fg: fg,
        }
    }
}

pub trait Widget : Any {
    fn draw(&self, renderer: &mut Renderer, focused: bool);
    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool;
}
<commit_msg>Have WidgetCore use builder methods for setting bg/fg while the contruction defaults on white bg and black fg<commit_after>use super::{Color, Event, Rect, Renderer};

use std::any::Any;
use std::cell::Cell;

pub struct WidgetCore {
    pub rect: Cell<Rect>,
    pub bg: Color,
    pub fg: Color,
}

impl WidgetCore {
    pub fn new() -> Self {
        WidgetCore {
            rect: Cell::new(Rect::default()),
            bg: Color::white(),
            fg: Color::black(),
        }
    }

    pub fn bg(mut self, color: Color) -> Self {
        self.bg = color;
        self
    }

    pub fn fg(mut self, color: Color) -> Self {
        self.fg = color;
        self
    }
}

pub trait Widget : Any {
    fn draw(&self, renderer: &mut Renderer, focused: bool);
    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool;
}
<|endoftext|>