<commit_before>// Copyright 2014 Dawid Ciężarkiewicz
// See LICENSE file for more information

use creature::{Creature};
use creature::{Race,Human,Scout,Grunt,Heavy};
use hex2d;
use hex2d::{Point,Position,Direction};
use hex2d::{Forward,Backward};
use map::{Tile,Map};
use map::{Wall,Floor,GlassWall,Sand};
use std::rand;
use std::rand::Rng;
use std::cell::{RefCell};
use std::rc::{Rc,Weak};
use std::vec::Vec;

pub type Creatures<'a> = Vec<Weak<RefCell<Creature<'a>>>>;

pub struct GameState<'a> {
    pub map : Box<Map<'a>>,
    pub player : Option<Weak<RefCell<Creature<'a>>>>,
    rng : rand::TaskRng,
    creatures: Creatures<'a>,
    tick : uint,
}

#[deriving(Show)]
pub enum Action {
    Run(Direction),
    Move(Direction),
    Turn(Direction),
    Melee(Direction),
    Use,
    Wait
}

impl<'a> GameState<'a> {
    pub fn new() -> GameState<'a> {
        let map = box hex2d::Map::new(100, 100, Tile {
            tiletype: Floor,
            creature: None,
        }
        );
        GameState {
            player: None,
            rng: rand::task_rng(),
            map: map,
            creatures: Vec::new(),
            tick: 0,
        }
    }

    fn spawn(&mut self, cr : Box<Creature>) -> Option<Rc<RefCell<Creature>>>  {
        if !self.map.at(*cr.p()).is_passable() {
            return None;
        }

        let p = *cr.p();
        let rc = Rc::new(RefCell::new(*cr));
        self.map.mut_at(p).creature = Some(rc.clone());
        self.creatures.push(rc.downgrade());
        Some(rc.clone())
    }

    fn spawn_random(&mut self, player : bool, race : Race) -> Rc<RefCell<Creature>> {
        loop {
            let pos = self.map.wrap(self.rng.gen::<Position>());
            let cr = box Creature::new(&*self.map, pos, player, race);
            match self.spawn(cr) {
                Some(cr) => return cr,
                None => {}
            }
        }
    }

    fn move_creature_if_possible(&mut self, cr : &mut Creature, pos : Position) {
        let cr_p = *cr.p();
        let pos_p = pos.p;
        if pos_p == cr_p {
            cr.pos_set(&*self.map, pos);
            return;
        }
        if !self.map.at(pos_p).is_passable() {
            return;
        }

        match self.map.at(pos_p).creature {
            Some(_) => { },
            None => {
                self.map.mut_at(pos_p).creature = self.map.at(cr_p).creature.clone();
                self.map.mut_at(cr_p).creature = None;
                cr.pos_set(&*self.map, pos);
            }
        }
    }

    pub fn tick(&mut self) {
        let mut creatures = self.creatures.clone();

        for cr in creatures.iter() {
            let creature = cr.upgrade();

            match creature.as_ref().map(|cr| cr.borrow_mut())  {
                Some(mut cr) => {
                    if cr.needs_action() {
                        assert!(!cr.is_player());
                        cr.update_los(&*self.map);
                        cr.update_action(&*self.map);
                    }
                    let action = cr.tick();
                    match action {
                        Some(action) => {
                            self.perform_action(&mut *cr, action);
                            cr.action_done();
                        },
                        None => {}
                    }
                },
                None => { }
            };
        }

        creatures.retain(
            |rc| {
                let rc = rc.upgrade();
                match rc.as_ref().map(|cr| cr.borrow()) {
                    Some(cr) => {
                        cr.is_alive()
                    },
                    None => false
                }
            }
            );
        self.creatures = creatures;
        self.tick += 1;
    }

    pub fn perform_action(&mut self, cr : &mut Creature, action : Action) {
        let old_pos = *cr.pos();
        cr.pos_prev_set(&*self.map, old_pos);

        match action {
            Turn(Forward)|Turn(Backward) => fail!("Illegal move"),
            Move(dir)|Run(dir) => {
                let pos = Position{ p: self.map.wrap(cr.p() + (cr.pos().dir + dir)), dir: cr.pos().dir };
                self.move_creature_if_possible(cr, pos)
            },
            Turn(dir) => {
                let pos = self.map.wrap(cr.pos() + dir);
                self.move_creature_if_possible(cr, pos)
            },
            Melee(dir) => {
                let target_p = self.map.wrap(cr.p() + (cr.pos().dir + dir));
                let target = self.map.mut_at(target_p).creature.as_ref().
                    map(|cr| cr.clone());
                if target.is_some() {
                    let target = target.unwrap();
                    let target = &mut *target.borrow_mut();
                    target.attacked_by(cr);
                    cr.attacked(target);

                    if !target.is_alive() {
                        self.map.mut_at(target_p).creature = None;
                    }
                }
            },
            _ => { }
        }
    }

    pub fn randomize_map(&mut self) {
        let height = self.map.height() as int;
        let width = self.map.width() as int;
        let area = width * height;

        for _ in range(0, area / 12) {
            let p = self.rng.gen::<Point>();
            let p = self.map.wrap(p);

            let t = match self.rng.gen_range(0u, 6) {
                0 => GlassWall,
                1 => Sand,
                _ => Wall
            };

            self.map.mut_at(p).tiletype = t;
            for &dir in hex2d::all_directions.iter() {
                let p = self.map.wrap(p + dir);
                self.map.mut_at(p).tiletype = t;
            }
        }

        for x in range(0i, width) {
            let p = Point::new(x, 0);
            self.map.mut_at(p).tiletype = Wall;
            let p = Point::new(x, height - 1);
            self.map.mut_at(p).tiletype = Wall;
        }

        for y in range(0i, height) {
            let p = Point::new(0, y);
            self.map.mut_at(p).tiletype = Wall;
            let p = Point::new(width - 1, y);
            self.map.mut_at(p).tiletype = Wall;
        }

        for _ in range(0, area / 200) {
            self.spawn_random(false, Scout);
        }

        for _ in range(0, self.map.width() * self.map.height() / 400) {
            self.spawn_random(false, Grunt);
        }

        for _ in range(0, self.map.width() * self.map.height() / 800) {
            self.spawn_random(false, Heavy);
        }

        let p = self.spawn_random(true, Human);

        self.player = Some(p.downgrade());
    }

    pub fn update_player_los(&self) {
        let pl = self.player.as_ref().and_then(|pl| pl.upgrade());
        if pl.is_some() {
            let pl = pl.unwrap();
            pl.borrow_mut().update_los(&*self.map);
        }
    }
}
<commit_msg>Small code refactoring.<commit_after>// Copyright 2014 Dawid Ciężarkiewicz
// See LICENSE file for more information

use creature::{Creature};
use creature::{Race,Human,Scout,Grunt,Heavy};
use hex2d;
use hex2d::{Point,Position,Direction};
use hex2d::{Forward,Backward};
use map::{Tile,Map};
use map::{Wall,Floor,GlassWall,Sand};
use std::rand;
use std::rand::Rng;
use std::cell::{RefCell};
use std::rc::{Rc,Weak};
use std::vec::Vec;

pub type Creatures<'a> = Vec<Weak<RefCell<Creature<'a>>>>;

pub struct GameState<'a> {
    pub map : Box<Map<'a>>,
    pub player : Option<Weak<RefCell<Creature<'a>>>>,
    rng : rand::TaskRng,
    creatures: Creatures<'a>,
    tick : uint,
}

#[deriving(Show)]
pub enum Action {
    Run(Direction),
    Move(Direction),
    Turn(Direction),
    Melee(Direction),
    Use,
    Wait
}

impl<'a> GameState<'a> {
    pub fn new() -> GameState<'a> {
        let map = box hex2d::Map::new(100, 100, Tile {
            tiletype: Floor,
            creature: None,
        }
        );
        GameState {
            player: None,
            rng: rand::task_rng(),
            map: map,
            creatures: Vec::new(),
            tick: 0,
        }
    }

    fn spawn(&mut self, cr : Box<Creature>) -> Option<Rc<RefCell<Creature>>>  {
        if !self.map.at(*cr.p()).is_passable() {
            return None;
        }

        let p = *cr.p();
        let rc = Rc::new(RefCell::new(*cr));
        self.map.mut_at(p).creature = Some(rc.clone());
        self.creatures.push(rc.downgrade());
        Some(rc.clone())
    }

    fn spawn_random(&mut self, player : bool, race : Race) -> Rc<RefCell<Creature>> {
        loop {
            let pos = self.map.wrap(self.rng.gen::<Position>());
            let cr = box Creature::new(&*self.map, pos, player, race);
            match self.spawn(cr) {
                Some(cr) => return cr,
                None => {}
            }
        }
    }

    fn move_creature_if_possible(&mut self, cr : &mut Creature, pos : Position) {
        let cr_p = *cr.p();
        let pos_p = pos.p;
        if pos_p == cr_p {
            cr.pos_set(&*self.map, pos);
            return;
        }
        if !self.map.at(pos_p).is_passable() {
            return;
        }

        match self.map.at(pos_p).creature {
            Some(_) => { },
            None => {
                self.map.mut_at(pos_p).creature = self.map.at(cr_p).creature.clone();
                self.map.mut_at(cr_p).creature = None;
                cr.pos_set(&*self.map, pos);
            }
        }
    }

    pub fn tick(&mut self) {
        let mut creatures = self.creatures.clone();

        for cr in creatures.iter() {
            let creature = cr.upgrade();

            match creature.as_ref().map(|cr| cr.borrow_mut())  {
                Some(mut cr) => {
                    if cr.needs_action() {
                        assert!(!cr.is_player());
                        cr.update_los(&*self.map);
                        cr.update_action(&*self.map);
                    }
                    let action = cr.tick();
                    match action {
                        Some(action) => {
                            self.perform_action(&mut *cr, action);
                            cr.action_done();
                        },
                        None => {}
                    }
                },
                None => { }
            };
        }

        creatures.retain(
            |rc| {
                let rc = rc.upgrade();
                match rc.as_ref().map(|cr| cr.borrow()) {
                    Some(cr) => {
                        cr.is_alive()
                    },
                    None => false
                }
            }
            );
        self.creatures = creatures;
        self.tick += 1;
    }

    pub fn perform_action(&mut self, cr : &mut Creature, action : Action) {
        let old_pos = *cr.pos();
        cr.pos_prev_set(&*self.map, old_pos);

        match action {
            Turn(Forward)|Turn(Backward) => fail!("Illegal move"),
            Move(dir)|Run(dir) => {
                let pos = Position{ p: self.map.wrap(cr.p() + (cr.pos().dir + dir)), dir: cr.pos().dir };
                self.move_creature_if_possible(cr, pos)
            },
            Turn(dir) => {
                let pos = self.map.wrap(cr.pos() + dir);
                self.move_creature_if_possible(cr, pos)
            },
            Melee(dir) => {
                let target_p = self.map.wrap(cr.p() + (cr.pos().dir + dir));
                let target = self.map.mut_at(target_p).creature.as_ref().
                    map(|cr| cr.clone());
                if target.is_some() {
                    let target = target.unwrap();
                    let target = &mut *target.borrow_mut();
                    target.attacked_by(cr);
                    cr.attacked(target);

                    if !target.is_alive() {
                        self.map.mut_at(target_p).creature = None;
                    }
                }
            },
            _ => { }
        }
    }

    pub fn randomize_map(&mut self) {
        let height = self.map.height() as int;
        let width = self.map.width() as int;
        let area = width * height;

        for _ in range(0, area / 12) {
            let p = self.rng.gen::<Point>();
            let p = self.map.wrap(p);

            let t = match self.rng.gen_range(0u, 6) {
                0 => GlassWall,
                1 => Sand,
                _ => Wall
            };

            self.map.mut_at(p).tiletype = t;
            for &dir in hex2d::all_directions.iter() {
                let p = self.map.wrap(p + dir);
                self.map.mut_at(p).tiletype = t;
            }
        }

        for x in range(0i, width) {
            let p = Point::new(x, 0);
            self.map.mut_at(p).tiletype = Wall;
            let p = Point::new(x, height - 1);
            self.map.mut_at(p).tiletype = Wall;
        }

        for y in range(0i, height) {
            let p = Point::new(0, y);
            self.map.mut_at(p).tiletype = Wall;
            let p = Point::new(width - 1, y);
            self.map.mut_at(p).tiletype = Wall;
        }

        for _ in range(0, area / 200) {
            self.spawn_random(false, Scout);
        }

        for _ in range(0, area / 400) {
            self.spawn_random(false, Grunt);
        }

        for _ in range(0, area / 800) {
            self.spawn_random(false, Heavy);
        }

        let p = self.spawn_random(true, Human);

        self.player = Some(p.downgrade());
    }

    pub fn update_player_los(&self) {
        let pl = self.player.as_ref().and_then(|pl| pl.upgrade());
        if pl.is_some() {
            let pl = pl.unwrap();
            pl.borrow_mut().update_los(&*self.map);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>do not unwrap texture loading of explosion; oops<commit_after><|endoftext|>


<commit_before><commit_msg>Add `new` method for `Texture`.<commit_after><|endoftext|>


<commit_before><commit_msg>Simplify half-byte check when parsing prefixes<commit_after><|endoftext|>


<commit_before><commit_msg>Refactors, functional and stylistic<commit_after><|endoftext|>


<commit_before><commit_msg>Refactor arg check<commit_after><|endoftext|>


<commit_before><commit_msg>updatedb<commit_after><|endoftext|>


<commit_before>fn main(expr: &str) -> i32 {
  let mut result = 0;
  let mut stack:Vec<i32> = Vec::new();
  for token in expr.split_whitespace() {
    let wrapped_operand = token.parse::<i32>();
    let is_operator = wrapped_operand.is_err();
    if is_operator {
      // xxxFlorent: Any way to destructure like this? Not sure of what I am doing below
      // let [ operand1, operand2 ] = stack.drain((token.len() - 3)..).collect();
      let operand1 = stack.pop().expect("expected i32 values only in stack");
      let operand2 = stack.pop().expect("expected i32 values only in stack");
      result += match token {
        "+" => operand1 + operand2,
        _ => panic!("unsupported operator")
      }
    } else {
      stack.push(wrapped_operand.unwrap());
    }
  }
  return result;
}

#[test]
fn it_adds() {
  let result = main("1 2 +");
  assert_eq!(result, 3);
}

#[test]
#[should_panic]
fn it_panics_for_unsupported_operators() {
  main("1 2 =");
  // xxxFlorent: How to test the panic message is right?
}
<commit_msg>More tests for panic cases<commit_after>fn main(expr: &str) -> i32 {
  let mut result = 0;
  let mut stack:Vec<i32> = Vec::new();
  for token in expr.split_whitespace() {
    let wrapped_operand = token.parse::<i32>();
    let is_operator = wrapped_operand.is_err();
    if is_operator {
      if stack.len() < 2 {
        panic!("Unsufficient operands before operator");
      }
      // xxxFlorent: Any way to destructure like this? Not sure of what I am doing below
      // let [ operand1, operand2 ] = stack.drain((token.len() - 3)..).collect();
      let operand1 = stack.pop().expect("expected i32 values only in stack");
      let operand2 = stack.pop().expect("expected i32 values only in stack");
      result += match token {
        "+" => operand1 + operand2,
        _ => panic!("Unsupported operator")
      }
    } else {
      stack.push(wrapped_operand.unwrap());
    }
  }

  if stack.len() > 0 {
    panic!("Remaining untreated operands. Probably missing operator.");
  }
  return result;
}

#[test]
fn it_adds() {
  let result = main("1 2 +");
  assert_eq!(result, 3);
}

#[test]
#[should_panic]
fn it_panics_for_unsupported_operators() {
  main("1 2 =");
  // xxxFlorent: How to test the panic message is right?
}

#[test]
#[should_panic]
fn it_panics_for_unsufficient_operands() {
  main("1 +");
  // xxxFlorent: How to test the panic message is right?
}

#[test]
#[should_panic]
fn it_panics_for_unsufficient_operators() {
  main("1 2 3 +");
  // xxxFlorent: How to test the panic message is right?
}
<|endoftext|>


<commit_before>extern crate hyper;

mod get;
mod post;

use hyper::{Get, Post};
use hyper::header;
use hyper::server::{Handler, Server, Request, Response};
use hyper::status::StatusCode;

struct HttpTin {
    server: String,
}

impl HttpTin {
    pub fn new() -> Self {
        let server = format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
        HttpTin { server: server }
    }

    fn prepare_response(&self, response: &mut Response) {
        let server = header::Server(self.server.clone());
        response.headers_mut().set(server);
    }
}

impl Handler for HttpTin {
    fn handle(&self, request: Request, mut response: Response) {
        println!("{} {} {}", request.remote_addr, request.method, request.uri);
        self.prepare_response(&mut response);
        match request.method {
            Get => get::get(request, response),
            Post => post::post(request, response),
            _ => *response.status_mut() = StatusCode::MethodNotAllowed,
        }
    }
}

fn main() {
    let server = Server::http("::1:8000").unwrap();
    // println!("Server {:?}", server);
    let active = server.handle(HttpTin::new()).unwrap();
    println!("Active {:?}", active.socket);
}
<commit_msg>Cleanup server start up and diagnostic<commit_after>extern crate hyper;

mod get;
mod post;

use hyper::{Get, Post};
use hyper::header;
use hyper::server::{Handler, Server, Request, Response};
use hyper::status::StatusCode;

struct HttpTin {
    server: String,
}

impl HttpTin {
    pub fn new() -> Self {
        let server = format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
        HttpTin { server: server }
    }

    fn prepare_response(&self, response: &mut Response) {
        let server = header::Server(self.server.clone());
        response.headers_mut().set(server);
    }
}

impl Handler for HttpTin {
    fn handle(&self, request: Request, mut response: Response) {
        println!("{} {} {}", request.remote_addr, request.method, request.uri);
        self.prepare_response(&mut response);
        match request.method {
            Get => get::get(request, response),
            Post => post::post(request, response),
            _ => *response.status_mut() = StatusCode::MethodNotAllowed,
        }
    }
}

fn main() {
    let server = Server::http("::1:8000").unwrap();
    if let Ok(active) = server.handle(HttpTin::new()) {
        println!("Listening on {:?}", active.socket);
    }
}
<|endoftext|>


<commit_before><commit_msg>Add major to slack notification<commit_after><|endoftext|>


<commit_before>extern crate hyper;
extern crate gradr_backend;

use hyper::Ipv4Addr;
use gradr_backend::notification_listener::{GitHubServer, NotificationSource};

#[cfg(not(test))]
fn main() {
    let server = GitHubServer::new(Ipv4Addr(0, 0, 0, 0), 1337);
    let running_server = server.event_loop().unwrap();
    loop {
        println!("{}", running_server.get_notification());
    }
}
<commit_msg>Added uncompiled code for the whole executable.<commit_after>extern crate hyper;
extern crate gradr_backend;

use std::sync::Arc;

use hyper::Ipv4Addr;

use gradr_backend::database::postgres_db::PostgresDatabase;
use gradr_backend::notification_listener::{GitHubServer, NotificationSource};
use gradr_backend::worker::worker_loop_step;

#[cfg(not(test))]
fn main() {
    let server = GitHubServer::new(Ipv4Addr(0, 0, 0, 0), 1337);
    let running_server = server.event_loop().unwrap();

    let db1 =
        Arc::new(
            PostgresDatabase::new(
                "postgres://jroesch@localhost/gradr-production").unwrap());
    let db2 = db1.clone();

    // thread for the notification listener
    spawn(proc() {
        loop {
            running_server.notification_event_loop_step(&*db1);
        }
    });

    // thread for the builder
    spawn(proc() {
        loop {
            worker_loop_step(&*db2);
        }
    });

    println!("THREADS STARTED");
}
<|endoftext|>


<commit_before>
extern crate civet;
extern crate conduit;
extern crate conduit_router;
extern crate cql_ffi;

use std::collections::HashMap;
use std::io::{self, Cursor};
use std::sync::mpsc::channel;

use cql_ffi::{CassCluster,CassSession};
use civet::{Config, response, Server};
use conduit::{Request, Response};
use conduit_router::{RouteBuilder, RequestParams};

const CONTACT_POINTS:&'static str = "127.0.0.1";

fn main() {
	let cluster = &CassCluster::new()
                        .set_contact_points(CONTACT_POINTS).unwrap()
                        .set_load_balance_round_robin().unwrap();

    let session_future = CassSession::new().connect(cluster).wait();

    match session_future {
   		Err(err) => panic!("{:?}",err),
        Ok(session) => {
			println!("session established");

		    let mut router = RouteBuilder::new();
    		router.get("/prepare/:statement", move |r: &mut Request| prepare(r, &session));
    		let _server = Server::start(Config { port: 8888, threads: 1 }, router);
    		let (_tx, rx) = channel::<()>();
    		rx.recv().unwrap();
		}
    }
}

fn prepare(req: &mut Request, session: &CassSession) -> io::Result<Response> {
	let name = req.params().find("statement").unwrap();
    let bytes = format!("Preparing: {}!", name).into_bytes();
     Ok(response(200, HashMap::new(), Cursor::new(bytes)))
}

<commit_msg>CassPrepared also needs to be Send<commit_after>
extern crate civet;
extern crate conduit;
extern crate conduit_router;
extern crate cql_ffi;

use std::collections::HashMap;
use std::io::Cursor;
use std::sync::mpsc::channel;

use cql_ffi::{CassCluster,CassSession,CassError,CassPrepared};
use civet::{Config, response, Server};
use conduit::{Request, Response};
use conduit_router::{RouteBuilder, RequestParams};

const CONTACT_POINTS:&'static str = "127.0.0.1";

fn main() {
	let cluster = &CassCluster::new()
                        .set_contact_points(CONTACT_POINTS).unwrap()
                        .set_load_balance_round_robin().unwrap();

    let session_future = CassSession::new().connect(cluster).wait();

    let all_prepared:Vec<CassPrepared> = Vec::new();

    match session_future {
   		Err(err) => panic!("{:?}",err),
        Ok(session) => {
			println!("session established");

		    let mut router = RouteBuilder::new();
    		router.get("/prepare/:statement", move |r: &mut Request| prepare(r, &session, &all_prepared));
    		let _server = Server::start(Config { port: 8888, threads: 1 }, router);
    		let (_tx, rx) = channel::<()>();
    		rx.recv().unwrap();
		}
    }
}

fn prepare(req: &mut Request, session: &CassSession, all_prepared:&Vec<CassPrepared>) -> Result<Response,CassError> {
	let statement = req.params().find("statement").unwrap();
	let prepared:CassPrepared = try!(try!(session.prepare(statement)).wait());
	//prepared.
    let bytes = format!("Preparing: {}!", statement).into_bytes();
     Ok(response(200, HashMap::new(), Cursor::new(bytes)))
}

<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate docopt;
extern crate gitrev;

use docopt::Docopt;

const USAGE: &'static str = "
GITREV is a utility program that is meant to serve as a replacement for
SubWCRev.exe.

Usage:
    gitrev.exe <src-version-file> <dst-version-file>
    gitrev.exe (-h | --help)
    gitrev.exe --version

Options:
    -h --help   Prints this message.
    --version   Prints version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_src_version_file: String,
    arg_dst_version_file: String,
}

fn main() {
    // Parse command line arguments
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    let curr_rev = gitrev::git_describe()
                          .unwrap_or_else(|e| panic!(e));
    let curr_branch = gitrev::git_branch()
                             .unwrap_or_else(|e| panic!(e));
    let remote_url = gitrev::git_remote_url()
                            .unwrap_or_else(|e| panic!(e));
    let build_time = gitrev::build_time()
                            .unwrap_or_else(|e| panic!(e));
    println!("Current revision: {}", curr_rev);
    println!("Build time: {}", build_time);
    println!("Current branch: {}", curr_branch);
    println!("Remote url: {}", remote_url);
}
<commit_msg>Prettify error output in case of a fatal error<commit_after>extern crate rustc_serialize;
extern crate docopt;
extern crate gitrev;

use docopt::Docopt;

const USAGE: &'static str = "
GITREV is a utility program that is meant to serve as a replacement for
SubWCRev.exe.

Usage:
    gitrev.exe <src-version-file> <dst-version-file>
    gitrev.exe (-h | --help)
    gitrev.exe --version

Options:
    -h --help   Prints this message.
    --version   Prints version.
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_src_version_file: String,
    arg_dst_version_file: String,
}

fn main() {
    // Parse command line arguments
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
    let curr_rev = gitrev::git_describe().unwrap_or_else(|e| {
        println!("{}", e);
        ::std::process::exit(1);
    });
    let curr_branch = gitrev::git_branch().unwrap_or_else(|e| {
        println!("{}", e);
        ::std::process::exit(1);
    });
    let remote_url = gitrev::git_remote_url().unwrap_or_else(|e| {
        println!("{}", e);
        ::std::process::exit(1);
    });
    let build_time = gitrev::build_time().unwrap_or_else(|e| {
        println!("{}", e);
        ::std::process::exit(1);
    });
    println!("Current revision: {}", curr_rev);
    println!("Build time: {}", build_time);
    println!("Current branch: {}", curr_branch);
    println!("Remote url: {}", remote_url);
}
<|endoftext|>


<commit_before>const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");

static FORMAT: &'static str = "{request-time}: {method} {uri} {status} {response-time}";

#[macro_use]
extern crate clap;
use clap::{Arg, ArgMatches, App, AppSettings, SubCommand};

extern crate toml;
extern crate rustc_serialize;
extern crate regex;

extern crate iron;
use iron::prelude::*;
use iron::Handler;
use iron::method::Method;
use std::str::FromStr;

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::{SimpleLogger, LogLevelFilter};

extern crate logger;
use logger::Logger;
use logger::Format;

extern crate notify;

use notify::{RecommendedWatcher, Watcher, RecursiveMode};
use notify::DebouncedEvent;
use notify::DebouncedEvent::{Create, Write};
use std::sync::mpsc::{channel, Receiver};
use std::time::Duration;

use std::thread;
use std::path::PathBuf;

mod config;
use config::{Config, ServerConfig, RequestConfig, ResponseConfig};
use std::collections::HashMap;
use std::ascii::AsciiExt;
mod error;
use error::HaxoniteError;
mod handlers;
use handlers::*;
mod utils;

use std::path::Path;

fn main() {
    let _ = SimpleLogger::init(LogLevelFilter::Info, simplelog::Config::default());

    match run() {
        Ok(_) => {}
        Err(err) => {
            error!("{}!", err);
            std::process::exit(-1);
        }
    }
}

fn run() -> Result<(), HaxoniteError> {
    let matches = define_command_line_options().get_matches();
    if let Some(matches) = matches.subcommand_matches("new") {
        let generate_full_project = matches.is_present("full");
        if let Some(project_name) = matches.value_of("project_name") {
            try!(utils::create_new_project(project_name, generate_full_project));
        }
        return Ok(());
    }

    if let Some(matches) = matches.subcommand_matches("serve") {
        try!(serve(matches, None));
    }
    if let Some(matches) = matches.subcommand_matches("watch") {
        try!(watch(matches));
    }
    Ok(())
}

fn serve(matches: &ArgMatches, rx_watcher: Option<Receiver<DebouncedEvent>>) -> Result<(), HaxoniteError> {
    let config_file = matches.value_of("config_file").unwrap_or("config.toml");
    'serve: loop {
        let config_content = try!(config::read_config(config_file));
        let config: Config = toml::decode_str(config_content.as_ref()).unwrap(); // TODO: remove unwrap to handle malformed config
        debug!("Using config: {:?}!", config);

        let server_config = config.server.unwrap_or_else(ServerConfig::default);
        let host = match value_t!(matches, "host", String) { // TODO: rewrite these matches
            Ok(host) => host,
            Err(_) => server_config.host.unwrap_or_else(config::default_host),
        };
        let port_number = match value_t!(matches, "port_number", u16) {
            Ok(port_number) => port_number,
            Err(_) => server_config.port.unwrap_or_else(config::default_port),
        };

        // Initialize Iron's router and pass it to config processing function to define routes
        let mut router = Router::new();
        let mut mount = Mount::new();
        match config.requests {
            Some(requests) => {
                try!(process_config_requests(&requests, &mut mount, &mut router));
            }
            None => return Err(HaxoniteError::NoRequestDefined),
        }
        mount.mount("/", router);

        // Insert logger middlewares before and after router
        let mut chain = Chain::new(mount);
        let format = Format::new(FORMAT);
        let (logger_before, logger_after) = Logger::new(Some(format.unwrap()));
        chain.link_before(logger_before);
        chain.link_after(logger_after);

        // Initialize Iron to process requests
        let mut _iron = try!(Iron::new(chain).http((host.as_ref(), port_number)));
        info!("Haxonite running on port: {}!", port_number);

        if let Some(ref rx_watcher) = rx_watcher {
            'watch: loop {
                match rx_watcher.recv() {
                    Ok(Create(path)) | Ok(Write(path)) => {
                        match PathBuf::from(&path).ends_with(config_file) {
                            true => {
                                info!("Reloading...");
                                _iron.close().expect("Iron cannot be closed");
                                thread::sleep(Duration::from_secs(1));
                                break 'watch
                            },
                            false => continue 'watch
                        }
                    },
                    Ok(_) => continue 'watch,
                    Err(e) => error!("watch error: {:?}", e),
                }
            }
        }
    }
}

fn watch(matches: &ArgMatches) -> Result<(), HaxoniteError> {
    let config_file = PathBuf::from(matches.value_of("config_file").unwrap_or("config.toml"));

    let (tx_watcher, rx_watcher) = channel();
    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx_watcher, Duration::from_secs(1)));
    let dir = config_file.parent().unwrap();
    try!(watcher.watch(dir, RecursiveMode::NonRecursive)); // NonRecursie as we only watch config file

    serve(matches, Some(rx_watcher))
}

fn process_config_requests(requests: &HashMap<String, RequestConfig>,
                           mut mount: &mut Mount,
                           mut router: &mut Router)
                           -> Result<(), HaxoniteError> {
    info!("Processing config!");
    for (request_name, request_config) in requests {
        info!("Processing config for {}: {:?}!",
              request_name,
              request_config);
        try!(define_route(request_name.clone(),
                          request_config.clone(),
                          &mut mount,
                          &mut router));
    }
    Ok(())
}

fn define_route(request_name: String, request_config: RequestConfig, mount: &mut Mount, router: &mut Router) -> Result<(), HaxoniteError> {
    let method = request_config.method.unwrap_or_else(config::default_method);
    let path = match request_config.path {
        Some(path) => path,
        None => return Err(HaxoniteError::NoPathDefined(request_name.clone())),
    };

    let type_ = request_config.type_.unwrap_or_else(config::default_type);
    let response_configs = match request_config.responses {
        Some(response_configs) => response_configs,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    let handler: Box<Handler> = match type_.as_ref() {
        "single" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            Box::new(try!(get_single_response_handler(request_name.clone(), response_config.clone())))
        }
        "random" => {
            let mut handler = RandomResponse::new();
            for response_config in &response_configs {
                let weight = response_config.weight.unwrap_or_else(config::default_weight);
                handler.add_handler(weight,
                                    try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "roundrobin" => {
            let mut handler = IteratingResponse::new("roundrobin");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "chain" => {
            let mut handler = IteratingResponse::new("chain");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "static" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            let response = match response_config.response {
                Some(ref response) => response,
                None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
            };
            let handler = Static::new(Path::new(&response));
            Box::new(handler)
        }
        _ => return Err(HaxoniteError::InvalidType(request_name.clone())),
    };

    match Method::from_str(method.to_ascii_uppercase().as_ref()) {
        Ok(Method::Extension(_)) |
        Err(_) => return Err(HaxoniteError::InvalidHTTPMethod(request_name.clone())),
        Ok(a) => {
            match type_.as_ref() {
                "static" => {
                    info!("Mounting static for: {} using {} type of handler.",
                          path,
                          type_);
                    mount.mount(path.as_ref(), handler);
                }
                _ => {
                    info!("Defining route for: {} using {} type of handler.",
                          path,
                          type_);
                    router.route(a, path.clone(), handler, request_name);
                }
            }
        }
    };
    Ok(())
}

fn get_single_response_handler(request_name: String, response_config: ResponseConfig) -> Result<SingleResponse, HaxoniteError> {
    let headers = process_headers(response_config.headers);
    let status = match response_config.status {
        Some(status) if status >= 100 && status <= 599 => status, // switch to Range's contains() when it will be stable
        Some(status) => return Err(HaxoniteError::InvalidHTTPStatus(request_name.clone(), status)),
        None => config::default_status(),
    };
    let response = match response_config.response {
        Some(response) => response,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    if !Path::new(&response).exists() {
        return Err(HaxoniteError::ResponseDoesNotExist(request_name.clone()));
    }
    Ok(SingleResponse::new(status, headers, response, response_config.delay))
}

fn process_headers(headers: Option<Vec<String>>) -> Vec<Vec<String>> {
    // TODO: This method should be optimized to not compile regex on every run,
    // not match on header when the default is used (it's valid)
    use regex::Regex;
    let re = Regex::new(r"([\w-]+):\s+([\w/]+)").unwrap();

    let headers = headers.unwrap_or_else(config::default_headers);
    headers.iter()
        .filter(|header| {
            if re.is_match(header) {
                true
            } else {
                warn!("Header {} is invalid (does not match \": \"). Skipping.",
                      header);
                false
            }
        })
        .map(|header| {
            header.split(": ")
                .map(// TODO: This is quite stupid and could be done with &str,
                     // but I decided to use String to not fight borrow checker for now...
                     |hdr| hdr.to_string())
                .collect()
        })
        .collect()
}

fn define_command_line_options<'a, 'b>() -> App<'a, 'b> {
    App::new("Haxonite")
        .setting(AppSettings::SubcommandRequired)
        .version(VERSION)
        .author(AUTHORS)
        .about("Easy API mocking")
        .subcommand(SubCommand::with_name("serve")
            .about("Starts Haxonite server")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("watch")
            .about("Starts Haxonite server with dynamic reload on change")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("new")
            .about("Create new Haxonite project")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("full")
                .help("Use to create a project with full config.toml file")
                .short("f")
                .long("full"))
            .arg(Arg::with_name("project_name")
                .help("Name of the project (will be used as a directory name)")
                .index(1)
                .required(true)))
}
<commit_msg>Remove unused import<commit_after>const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const AUTHORS: &'static str = env!("CARGO_PKG_AUTHORS");

static FORMAT: &'static str = "{request-time}: {method} {uri} {status} {response-time}";

#[macro_use]
extern crate clap;
use clap::{Arg, ArgMatches, App, AppSettings, SubCommand};

extern crate toml;
extern crate rustc_serialize;
extern crate regex;

extern crate iron;
use iron::prelude::*;
use iron::Handler;
use iron::method::Method;
use std::str::FromStr;

extern crate router;
use router::Router;

extern crate staticfile;
use staticfile::Static;

extern crate mount;
use mount::Mount;

#[macro_use]
extern crate log;
extern crate simplelog;
use simplelog::{SimpleLogger, LogLevelFilter};

extern crate logger;
use logger::Logger;
use logger::Format;

extern crate notify;

use notify::{RecommendedWatcher, Watcher, RecursiveMode};
use notify::DebouncedEvent;
use notify::DebouncedEvent::{Create, Write};
use std::sync::mpsc::{channel, Receiver};
use std::time::Duration;

use std::thread;
use std::path::PathBuf;

mod config;
use config::{Config, ServerConfig, RequestConfig, ResponseConfig};
use std::collections::HashMap;
mod error;
use error::HaxoniteError;
mod handlers;
use handlers::*;
mod utils;

use std::path::Path;

fn main() {
    let _ = SimpleLogger::init(LogLevelFilter::Info, simplelog::Config::default());

    match run() {
        Ok(_) => {}
        Err(err) => {
            error!("{}!", err);
            std::process::exit(-1);
        }
    }
}

fn run() -> Result<(), HaxoniteError> {
    let matches = define_command_line_options().get_matches();
    if let Some(matches) = matches.subcommand_matches("new") {
        let generate_full_project = matches.is_present("full");
        if let Some(project_name) = matches.value_of("project_name") {
            try!(utils::create_new_project(project_name, generate_full_project));
        }
        return Ok(());
    }

    if let Some(matches) = matches.subcommand_matches("serve") {
        try!(serve(matches, None));
    }
    if let Some(matches) = matches.subcommand_matches("watch") {
        try!(watch(matches));
    }
    Ok(())
}

fn serve(matches: &ArgMatches, rx_watcher: Option<Receiver<DebouncedEvent>>) -> Result<(), HaxoniteError> {
    let config_file = matches.value_of("config_file").unwrap_or("config.toml");
    'serve: loop {
        let config_content = try!(config::read_config(config_file));
        let config: Config = toml::decode_str(config_content.as_ref()).unwrap(); // TODO: remove unwrap to handle malformed config
        debug!("Using config: {:?}!", config);

        let server_config = config.server.unwrap_or_else(ServerConfig::default);
        let host = match value_t!(matches, "host", String) { // TODO: rewrite these matches
            Ok(host) => host,
            Err(_) => server_config.host.unwrap_or_else(config::default_host),
        };
        let port_number = match value_t!(matches, "port_number", u16) {
            Ok(port_number) => port_number,
            Err(_) => server_config.port.unwrap_or_else(config::default_port),
        };

        // Initialize Iron's router and pass it to config processing function to define routes
        let mut router = Router::new();
        let mut mount = Mount::new();
        match config.requests {
            Some(requests) => {
                try!(process_config_requests(&requests, &mut mount, &mut router));
            }
            None => return Err(HaxoniteError::NoRequestDefined),
        }
        mount.mount("/", router);

        // Insert logger middlewares before and after router
        let mut chain = Chain::new(mount);
        let format = Format::new(FORMAT);
        let (logger_before, logger_after) = Logger::new(Some(format.unwrap()));
        chain.link_before(logger_before);
        chain.link_after(logger_after);

        // Initialize Iron to process requests
        let mut _iron = try!(Iron::new(chain).http((host.as_ref(), port_number)));
        info!("Haxonite running on port: {}!", port_number);

        if let Some(ref rx_watcher) = rx_watcher {
            'watch: loop {
                match rx_watcher.recv() {
                    Ok(Create(path)) | Ok(Write(path)) => {
                        match PathBuf::from(&path).ends_with(config_file) {
                            true => {
                                info!("Reloading...");
                                _iron.close().expect("Iron cannot be closed");
                                thread::sleep(Duration::from_secs(1));
                                break 'watch
                            },
                            false => continue 'watch
                        }
                    },
                    Ok(_) => continue 'watch,
                    Err(e) => error!("watch error: {:?}", e),
                }
            }
        }
    }
}

fn watch(matches: &ArgMatches) -> Result<(), HaxoniteError> {
    let config_file = PathBuf::from(matches.value_of("config_file").unwrap_or("config.toml"));

    let (tx_watcher, rx_watcher) = channel();
    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx_watcher, Duration::from_secs(1)));
    let dir = config_file.parent().unwrap();
    try!(watcher.watch(dir, RecursiveMode::NonRecursive)); // NonRecursie as we only watch config file

    serve(matches, Some(rx_watcher))
}

fn process_config_requests(requests: &HashMap<String, RequestConfig>,
                           mut mount: &mut Mount,
                           mut router: &mut Router)
                           -> Result<(), HaxoniteError> {
    info!("Processing config!");
    for (request_name, request_config) in requests {
        info!("Processing config for {}: {:?}!",
              request_name,
              request_config);
        try!(define_route(request_name.clone(),
                          request_config.clone(),
                          &mut mount,
                          &mut router));
    }
    Ok(())
}

fn define_route(request_name: String, request_config: RequestConfig, mount: &mut Mount, router: &mut Router) -> Result<(), HaxoniteError> {
    let method = request_config.method.unwrap_or_else(config::default_method);
    let path = match request_config.path {
        Some(path) => path,
        None => return Err(HaxoniteError::NoPathDefined(request_name.clone())),
    };

    let type_ = request_config.type_.unwrap_or_else(config::default_type);
    let response_configs = match request_config.responses {
        Some(response_configs) => response_configs,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    let handler: Box<Handler> = match type_.as_ref() {
        "single" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            Box::new(try!(get_single_response_handler(request_name.clone(), response_config.clone())))
        }
        "random" => {
            let mut handler = RandomResponse::new();
            for response_config in &response_configs {
                let weight = response_config.weight.unwrap_or_else(config::default_weight);
                handler.add_handler(weight,
                                    try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "roundrobin" => {
            let mut handler = IteratingResponse::new("roundrobin");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "chain" => {
            let mut handler = IteratingResponse::new("chain");
            for response_config in &response_configs {
                handler.add_handler(try!(get_single_response_handler(request_name.clone(), response_config.clone())));
            }
            Box::new(handler)
        }
        "static" => {
            let response_config = try!(response_configs.first()
                .ok_or(HaxoniteError::NoResponseDefined(request_name.clone())));
            let response = match response_config.response {
                Some(ref response) => response,
                None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
            };
            let handler = Static::new(Path::new(&response));
            Box::new(handler)
        }
        _ => return Err(HaxoniteError::InvalidType(request_name.clone())),
    };

    match Method::from_str(method.to_ascii_uppercase().as_ref()) {
        Ok(Method::Extension(_)) |
        Err(_) => return Err(HaxoniteError::InvalidHTTPMethod(request_name.clone())),
        Ok(a) => {
            match type_.as_ref() {
                "static" => {
                    info!("Mounting static for: {} using {} type of handler.",
                          path,
                          type_);
                    mount.mount(path.as_ref(), handler);
                }
                _ => {
                    info!("Defining route for: {} using {} type of handler.",
                          path,
                          type_);
                    router.route(a, path.clone(), handler, request_name);
                }
            }
        }
    };
    Ok(())
}

fn get_single_response_handler(request_name: String, response_config: ResponseConfig) -> Result<SingleResponse, HaxoniteError> {
    let headers = process_headers(response_config.headers);
    let status = match response_config.status {
        Some(status) if status >= 100 && status <= 599 => status, // switch to Range's contains() when it will be stable
        Some(status) => return Err(HaxoniteError::InvalidHTTPStatus(request_name.clone(), status)),
        None => config::default_status(),
    };
    let response = match response_config.response {
        Some(response) => response,
        None => return Err(HaxoniteError::NoResponseDefined(request_name.clone())),
    };
    if !Path::new(&response).exists() {
        return Err(HaxoniteError::ResponseDoesNotExist(request_name.clone()));
    }
    Ok(SingleResponse::new(status, headers, response, response_config.delay))
}

fn process_headers(headers: Option<Vec<String>>) -> Vec<Vec<String>> {
    // TODO: This method should be optimized to not compile regex on every run,
    // not match on header when the default is used (it's valid)
    use regex::Regex;
    let re = Regex::new(r"([\w-]+):\s+([\w/]+)").unwrap();

    let headers = headers.unwrap_or_else(config::default_headers);
    headers.iter()
        .filter(|header| {
            if re.is_match(header) {
                true
            } else {
                warn!("Header {} is invalid (does not match \": \"). Skipping.",
                      header);
                false
            }
        })
        .map(|header| {
            header.split(": ")
                .map(// TODO: This is quite stupid and could be done with &str,
                     // but I decided to use String to not fight borrow checker for now...
                     |hdr| hdr.to_string())
                .collect()
        })
        .collect()
}

fn define_command_line_options<'a, 'b>() -> App<'a, 'b> {
    App::new("Haxonite")
        .setting(AppSettings::SubcommandRequired)
        .version(VERSION)
        .author(AUTHORS)
        .about("Easy API mocking")
        .subcommand(SubCommand::with_name("serve")
            .about("Starts Haxonite server")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("watch")
            .about("Starts Haxonite server with dynamic reload on change")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("host")
                 .short("h")
                 .long("host")
                 .value_name("HOST")
                 .help("Run Haxonite on the host. Default: localhost.")
                 .takes_value(true))
            .arg(Arg::with_name("port_number")
                 .short("p")
                 .long("port")
                 .value_name("PORT")
                 .help("Run Haxonite on the specified port. Default: 4000.")
                 .takes_value(true))
            .arg(Arg::with_name("config_file")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Sets a custom config file. Default: config.toml.")
                 .takes_value(true)))
        .subcommand(SubCommand::with_name("new")
            .about("Create new Haxonite project")
            .version(VERSION)
            .author(AUTHORS)
            .arg(Arg::with_name("full")
                .help("Use to create a project with full config.toml file")
                .short("f")
                .long("full"))
            .arg(Arg::with_name("project_name")
                .help("Name of the project (will be used as a directory name)")
                .index(1)
                .required(true)))
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate js_types;
extern crate jsrs_common;
extern crate jsrs_parser;
extern crate french_press;
extern crate test;

extern crate rustyline;

mod bench;
mod coerce;
mod eval;

use std::env;
use std::io::prelude::*;
use std::process::exit;
use std::io::{self, BufReader};
use std::path::Path;
use std::fs::{File, metadata};

use rustyline::error::ReadlineError;
use rustyline::Editor;

use french_press::{init_gc, ScopeManager};
use js_types::js_var::JsType::JsUndef;

use eval::eval_string;

fn eval_file(filename: String, debug: bool, mut scope_manager: &mut ScopeManager) {
    println!("Reading from \"{}\"", filename);
    let path = Path::new(&filename);
    let file = File::open(&path)
        .expect(&format!("Cannot open \"{}\": no such file or directory", filename));
    let file_buffer = BufReader::new(file);

    for line in file_buffer.lines() {
        let mut input = String::from(line.unwrap().trim());

        if debug {
            println!(">> {:?}", input);
        }

        // insert semicolon if necessary
        if !input.ends_with(";") && !input.ends_with("}") {
            input.push_str(";");
        }

        if debug {
            println!("=> {:?}", eval_string(&input, &mut scope_manager));
            //println!("** {:?}", state);
        }
    }
}

fn repl(mut scope_manager: &mut ScopeManager) -> i32 {
    let mut rl = Editor::new();
    let mut stderr = io::stderr();

    scope_manager.push_scope();

    if metadata(".history").is_ok() && rl.load_history(".history").is_err() {
        writeln!(stderr, "Error: unable to load history on startup").unwrap();
    }

    loop {
        // prompt
        let readline = rl.readline(">> ");

        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                let mut input = String::from(line.trim());

                // ignore if only whitespace
                if input.len() == 0 {
                    continue;
                }

                rl.add_history_entry(&input);

                // insert semicolon if necessary
                if !input.ends_with(";") && !input.ends_with("}") {
                    input.push_str(";");
                }

                println!("=> {:?}", eval_string(&input, &mut scope_manager).t);
            },
            Err(ReadlineError::Interrupted) => {
                if rl.save_history(".history").is_err() {
                    writeln!(stderr, "Error: unable to save history on exit").unwrap();
                    return 2;
                }
                return 1;
            },
            Err(ReadlineError::Eof) => {
                if rl.save_history(".history").is_err() {
                    writeln!(stderr, "Error: unable to save history on exit").unwrap();
                    return 2;
                }
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);

                if rl.save_history(".history").is_err() {
                    writeln!(stderr, "Error: unable to save history on exit").unwrap();
                    return 2;
                }
                return 3;
            }
        }
    }
    0
}

fn main() {
    let mut scope_manager = init_gc();

    let args = env::args();
    if args.len() > 1 {
        for file in args.skip(1) {
            eval_file(file, false, &mut scope_manager);
        }
    } else {
        let ret = repl(&mut scope_manager);
        exit(ret)
    }
}
<commit_msg>Call repl from eval_file.<commit_after>#![feature(test)]

extern crate js_types;
extern crate jsrs_common;
extern crate jsrs_parser;
extern crate french_press;
extern crate test;

extern crate rustyline;

mod bench;
mod coerce;
mod eval;

use std::env;
use std::io::prelude::*;
use std::process::exit;
use std::io::{self, BufReader};
use std::path::Path;
use std::fs::{File, metadata};

use rustyline::error::ReadlineError;
use rustyline::Editor;

use french_press::{init_gc, ScopeManager};
use js_types::js_var::JsType::JsUndef;

use eval::eval_string;

fn eval_file(filename: String, debug: bool,
             mut scope_manager: &mut ScopeManager) {
    println!("Reading from \"{}\"", filename);
    let path = Path::new(&filename);
    let file = File::open(&path)
        .expect(&format!("Cannot open \"{}\": no such file or directory", filename));
    let file_buffer = BufReader::new(file);

    for line in file_buffer.lines() {
        let mut input = String::from(line.unwrap().trim());

        if debug {
            println!(">> {:?}", input);
        }

        // insert semicolon if necessary
        if !input.ends_with(";") && !input.ends_with("}") {
            input.push_str(";");
        }

        let ret = eval_string(&input, &mut scope_manager);
        if debug {
            println!("=> {:?}", ret);
        }
    }
    repl(scope_manager);
}

fn repl(mut scope_manager: &mut ScopeManager) -> i32 {
    let mut rl = Editor::new();
    let mut stderr = io::stderr();

    scope_manager.push_scope();

    if metadata(".history").is_ok() && rl.load_history(".history").is_err() {
        writeln!(stderr, "Error: unable to load history on startup").unwrap();
    }

    loop {
        // prompt
        let readline = rl.readline(">> ");

        match readline {
            Ok(line) => {
                rl.add_history_entry(&line);
                let mut input = String::from(line.trim());

                // ignore if only whitespace
                if input.len() == 0 {
                    continue;
                }

                rl.add_history_entry(&input);

                // insert semicolon if necessary
                if !input.ends_with(";") && !input.ends_with("}") {
                    input.push_str(";");
                }

                println!("=> {:?}", eval_string(&input, &mut scope_manager).t);
            },
            Err(ReadlineError::Interrupted) => {
                if rl.save_history(".history").is_err() {
                    writeln!(stderr, "Error: unable to save history on exit").unwrap();
                    return 2;
                }
                return 1;
            },
            Err(ReadlineError::Eof) => {
                if rl.save_history(".history").is_err() {
                    writeln!(stderr, "Error: unable to save history on exit").unwrap();
                    return 2;
                }
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);

                if rl.save_history(".history").is_err() {
                    writeln!(stderr, "Error: unable to save history on exit").unwrap();
                    return 2;
                }
                return 3;
            }
        }
    }
    0
}

fn main() {
    let mut scope_manager = init_gc();

    let args = env::args();
    if args.len() > 1 {
        for file in args.skip(1) {
            eval_file(file, false, &mut scope_manager);
        }
    } else {
        let ret = repl(&mut scope_manager);
        exit(ret)
    }
}
<|endoftext|>


<commit_before>#![feature(plugin, custom_derive, decl_macro)]
#![plugin(rocket_codegen)]
extern crate ip_manager;
extern crate rocket;
extern crate rocket_contrib;
extern crate serde_json;

use rocket::request::LenientForm;
use ip_manager::Result;
use ip_manager::{handle_command, handle_submission};
use ip_manager::slack::slash_command::Request;
use ip_manager::slack::dialog::{Submission, SubmissionResponse};

fn main() {
    rocket::ignite()
        .mount("/ip-manager/command", routes![command_request])
        .mount("/ip-manager/submission", routes![dialog_response])
        .mount("/ip-manager/ping", routes![ping])
        .launch();
}

#[post("/<command>", data = "<form>")]
fn command_request(command: String, form: LenientForm<Request>) -> Result<rocket_contrib::Json> {
    let data = form.into_inner();
    let json = handle_command(&command, data)?;
    Ok(rocket_contrib::Json(json))
}

#[post("/", data = "<form>")]
fn dialog_response(form: LenientForm<SubmissionResponse>) -> Result<String> {
    let data: Submission = serde_json::from_str(&form.into_inner().payload).unwrap();
    handle_submission(data)?;
    Ok("".to_owned())
}

#[post("/")]
fn ping() -> String {
    "pong".to_owned()
}
<commit_msg>no prefix<commit_after>#![feature(plugin, custom_derive, decl_macro)]
#![plugin(rocket_codegen)]
extern crate ip_manager;
extern crate rocket;
extern crate rocket_contrib;
extern crate serde_json;

use rocket::request::LenientForm;
use ip_manager::Result;
use ip_manager::{handle_command, handle_submission};
use ip_manager::slack::slash_command::Request;
use ip_manager::slack::dialog::{Submission, SubmissionResponse};

fn main() {
    rocket::ignite()
        .mount("/command", routes![command_request])
        .mount("/submission", routes![dialog_response])
        .mount("/ping", routes![ping])
        .launch();
}

#[post("/<command>", data = "<form>")]
fn command_request(command: String, form: LenientForm<Request>) -> Result<rocket_contrib::Json> {
    let data = form.into_inner();
    let json = handle_command(&command, data)?;
    Ok(rocket_contrib::Json(json))
}

#[post("/", data = "<form>")]
fn dialog_response(form: LenientForm<SubmissionResponse>) -> Result<String> {
    let data: Submission = serde_json::from_str(&form.into_inner().payload).unwrap();
    handle_submission(data)?;
    Ok("".to_owned())
}

#[post("/")]
fn ping() -> String {
    "pong".to_owned()
}
<|endoftext|>


<commit_before>/// Easy to use Let's Encrypt client to issue and renew TLS certs

extern crate acme_client;
extern crate openssl;
extern crate clap;
extern crate env_logger;
extern crate openssl_sys;

use std::io;
use std::path::Path;
use std::collections::HashSet;
use acme_client::Directory;
use acme_client::error::Result;
use clap::{Arg, App, SubCommand, ArgMatches};

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .usage("acme-client sign -D example.org -P /var/www -k domain.key -o domain.crt\
                \n    acme-client revoke -K user_or_domain.key -C signed.crt")
        .subcommand(SubCommand::with_name("sign")
            .about("Signs a certificate")
            .display_order(1)
            .arg(Arg::with_name("USER_KEY_PATH")
                .help("User private key path to use it in account registration.")
                .long("user-key")
                .short("U")
                .takes_value(true))
            .arg(Arg::with_name("DOMAIN_KEY_PATH")
                .help("Domain private key path to use it in CSR generation.")
                .short("K")
                .long("domain-key")
                .takes_value(true))
            .arg(Arg::with_name("DOMAIN")
                .help("Domain name to obtain certificate. You can use more than one domain name.")
                .short("D")
                .long("domain")
                .multiple(true)
                .takes_value(true))
            .arg(Arg::with_name("PUBLIC_DIR")
                .help("Directory to save ACME simple http challenge. This option is required.")
                .short("P")
                .long("public-dir")
                .takes_value(true))
            .arg(Arg::with_name("EMAIL")
                .help("Contact email address (optional).")
                .short("E")
                .long("email")
                .takes_value(true))
            .arg(Arg::with_name("DOMAIN_CSR")
                .help("Path to domain certificate signing request.")
                .short("C")
                .long("domain-csr")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_USER_KEY")
                .help("Path to save private user key.")
                .long("save-user-key")
                .short("u")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_DOMAIN_KEY")
                .help("Path to save domain private key.")
                .short("k")
                .long("save-domain-key")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_DOMAIN_CSR")
                .help("Path to save domain certificate signing request.")
                .long("save-csr")
                .short("S")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_SIGNED_CERTIFICATE")
                .help("Path to save signed certificate. Default is STDOUT.")
                .short("o")
                .long("save-crt")
                .takes_value(true))
            .arg(Arg::with_name("CHAIN")
                .help("Chains the signed certificate with Let's Encrypt Authority X3 \
                       (IdenTrust cross-signed) intermediate certificate.")
                .short("c")
                .long("chain")
                .takes_value(false))
            .arg(Arg::with_name("DNS_CHALLENGE")
                 .help("Use DNS challenge instead of HTTP. This option requires user \
                        to generate a TXT record for domain")
                 .short("d")
                 .long("dns")
                 .takes_value(false)))
        .subcommand(SubCommand::with_name("revoke")
            .about("Revokes a signed certificate")
            .display_order(2)
            .arg(Arg::with_name("USER_KEY")
                .help("User or domain private key path.")
                .long("user-key")
                .short("K")
                .required(true)
                .takes_value(true))
            .arg(Arg::with_name("SIGNED_CRT")
                .help("Path to signed domain certificate to revoke.")
                .long("signed-crt")
                .short("C")
                .required(true)
                .takes_value(true)))
        .arg(Arg::with_name("verbose")
             .help("Show verbose output")
             .short("v")
             .multiple(true))
        .get_matches();

    init_logger(matches.occurrences_of("verbose"));

    let res = if let Some(matches) = matches.subcommand_matches("sign") {
        sign_certificate(matches)
    } else if let Some(matches) = matches.subcommand_matches("revoke") {
        revoke_certificate(matches)
    } else {
        println!("{}", matches.usage());
        Ok(())
    };

    if let Err(e) = res {
        eprintln!("{}", e);
        ::std::process::exit(1);
    }
}

fn sign_certificate(matches: &ArgMatches) -> Result<()> {
    let directory = Directory::lets_encrypt()?;

    let mut account_registration = directory.account_registration();

    if let Some(email) = matches.value_of("EMAIL") {
        account_registration = account_registration.email(email);
    }

    if let Some(user_key_path) = matches.value_of("USER_KEY_PATH") {
        account_registration = account_registration.pkey_from_file(user_key_path)?;
    }

    let account = account_registration.register()?;

    // get domain names from --csr or --domain arguments
    // FIXME: there is so many unncessary string conversations in the following code
    let domains: Vec<String> = if let Some(csr_path) = matches.value_of("DOMAIN_CSR") {
        names_from_csr(csr_path)?.into_iter().collect()
    } else {
        matches.values_of("DOMAIN")
            .ok_or("You need to provide at least one domain name")?.map(|s| s.to_owned()).collect()
    };

    // domains would be empty if provided --csr doesn't contain any
    if domains.is_empty() {
        return Err("You need to provide at least one domain name with --domain argument \
                   or from --csr".into());
    }

    for domain in &domains {
        let authorization = account.authorization(domain)?;
        if !matches.is_present("DNS_CHALLENGE") {
            let challenge = authorization.get_http_challenge().ok_or("HTTP challenge not found")?;
            challenge.save_key_authorization(matches.value_of("PUBLIC_DIR")
                                                 .ok_or("--public-dir not defined. \
                                                            You need to define a public \
                                                            directory to use http challenge \
                                                            verification")?)?;
            challenge.validate()?;
        } else {
            let challenge = authorization.get_dns_challenge().ok_or("DNS challenge not found")?;
            println!("Please create a TXT record for _acme-challenge.{}: {}\n\
                      Press enter to continue",
                     domain,
                     challenge.signature()?);
            io::stdin().read_line(&mut String::new()).unwrap();
            challenge.validate()?;
        }
    }

    let dv: Vec<&str> = domains.iter().map(String::as_str).collect();
    let mut certificate_signer = account.certificate_signer(dv.as_slice());

    if let Some(domain_key_path) = matches.value_of("DOMAIN_KEY_PATH") {
        if let Some(csr_path) = matches.value_of("DOMAIN_CSR") {
            certificate_signer = certificate_signer.csr_from_file(domain_key_path, csr_path)?;
        } else {
            certificate_signer = certificate_signer.pkey_from_file(domain_key_path)?;
        }
    }

    let certificate = certificate_signer.sign_certificate()?;
    let signed_certificate_path = matches.value_of("SAVE_SIGNED_CERTIFICATE")
        .ok_or("You need to save signed certificate")?;
    if matches.is_present("CHAIN") {
        certificate.save_signed_certificate_and_chain(None, signed_certificate_path)?;
    } else {
        certificate.save_signed_certificate(signed_certificate_path)?;
    }

    if let Some(path) = matches.value_of("SAVE_DOMAIN_KEY") {
        certificate.save_private_key(path)?;
    }
    if let Some(path) = matches.value_of("SAVE_DOMAIN_CSR") {
        certificate.save_csr(path)?;
    }
    if let Some(path) = matches.value_of("SAVE_USER_KEY") {
        account.save_private_key(path)?;
    }

    Ok(())
}

fn revoke_certificate(matches: &ArgMatches) -> Result<()> {
    let directory = Directory::lets_encrypt()?;
    let account = directory.account_registration()
        .pkey_from_file(matches.value_of("USER_KEY")
                            .ok_or("You need to provide user \
                                   or domain private key used \
                                   to sign certificate.")?)?
        .register()?;
    account.revoke_certificate_from_file(matches.value_of("SIGNED_CRT")
                                             .ok_or("You need to provide \
                                                    a signed certificate to \
                                                    revoke.")?)?;
    Ok(())
}

fn init_logger(level: u64) {
    let level = match level {
        0 => "",
        1 => "acme_client=info",
        _ => "acme_client=debug",
    };
    let mut builder = env_logger::LogBuilder::new();
    builder.parse(&::std::env::var("RUST_LOG").unwrap_or(level.to_owned()));
    let _ = builder.init();
}

fn names_from_csr<P: AsRef<Path>>(csr_path: P) -> Result<HashSet<String>> {
    use std::fs::File;
    use std::io::Read;
    use std::slice;
    use openssl::x509::{X509Req, X509Extension};
    use openssl::nid;
    use openssl::stack::Stack;
    use openssl::types::OpenSslTypeRef;
    use std::os::raw::{c_int, c_long, c_uchar};
    use openssl::types::OpenSslType;

    fn read_file<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {
        let mut file = File::open(path)?;
        let mut content = Vec::new();
        file.read_to_end(&mut content)?;
        Ok(content)
    }

    let csr = X509Req::from_pem(&read_file(csr_path)?)?;

    let mut names = HashSet::new();

    // add CN to names first
    if let Some(cn) = csr.subject_name().entries_by_nid(nid::COMMONNAME).nth(0) {
        names.insert(String::from_utf8_lossy(cn.data().as_slice()).into_owned());
    }

    unsafe {
        #[repr(C)]
        struct Asn1StringSt {
            length: c_int,
            type_: c_int,
            data: *mut c_uchar,
            flags: c_long
        }
        extern "C" {
            fn X509_REQ_get_extensions(
                req: *mut openssl_sys::X509_REQ
            ) -> *mut openssl_sys::stack_st_X509_EXTENSION;
            fn X509v3_get_ext_by_NID(
                x: *const openssl_sys::stack_st_X509_EXTENSION,
                nid: c_int,
                lastpos: c_int
            ) -> c_int;
            fn X509_EXTENSION_get_data(
                ne: *mut openssl_sys::X509_EXTENSION,
            ) -> *mut Asn1StringSt;
        }
        let extensions = X509_REQ_get_extensions(csr.as_ptr());
        if !extensions.is_null() {
            let san_extension_idx = X509v3_get_ext_by_NID(extensions,
                                                          openssl_sys::NID_subject_alt_name,
                                                          -1);
            if let Some(san_extension) = Stack::<X509Extension>::from_ptr(extensions)
                .iter().nth(san_extension_idx as usize) {

                let extension_data = X509_EXTENSION_get_data(san_extension.as_ptr());
                let slc = slice::from_raw_parts((*extension_data).data,
                                                (*extension_data).length as usize);
                parse_asn1_octet_str(slc).iter().for_each(|n| {
                    names.insert(n.to_string());
                });
            }
        }
    }

    Ok(names)
}

fn parse_asn1_octet_str(s: &[u8]) -> Vec<String> {
    let mut iter = s.split(|n| *n == 130);
    let mut names = Vec::new();
    if iter.next().is_some() {
        for s in iter {
            let mut v = s.to_vec();
            v.remove(0); // remove first element which is length
            let name = String::from_utf8_lossy(&v);
            names.push(name.into_owned());
        }
    }
    names
}

#[test]
fn test_names_from_csr() {
    let _ = env_logger::init();
    let mut names = HashSet::new();
    names.insert("cn.example.com".to_owned());
    names.insert("www.example.com".to_owned());
    names.insert("example.com".to_owned());
    let names_from_csr = names_from_csr("tests/domain_with_san.csr").unwrap();
    assert_eq!(names, names_from_csr);
}
<commit_msg>Check domains before doing anything<commit_after>/// Easy to use Let's Encrypt client to issue and renew TLS certs

extern crate acme_client;
extern crate openssl;
extern crate clap;
extern crate env_logger;
extern crate openssl_sys;

use std::io;
use std::path::Path;
use std::collections::HashSet;
use acme_client::Directory;
use acme_client::error::Result;
use clap::{Arg, App, SubCommand, ArgMatches};

fn main() {
    let matches = App::new(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
        .usage("acme-client sign -D example.org -P /var/www -k domain.key -o domain.crt\
                \n    acme-client revoke -K user_or_domain.key -C signed.crt")
        .subcommand(SubCommand::with_name("sign")
            .about("Signs a certificate")
            .display_order(1)
            .arg(Arg::with_name("USER_KEY_PATH")
                .help("User private key path to use it in account registration.")
                .long("user-key")
                .short("U")
                .takes_value(true))
            .arg(Arg::with_name("DOMAIN_KEY_PATH")
                .help("Domain private key path to use it in CSR generation.")
                .short("K")
                .long("domain-key")
                .takes_value(true))
            .arg(Arg::with_name("DOMAIN")
                .help("Domain name to obtain certificate. You can use more than one domain name.")
                .short("D")
                .long("domain")
                .multiple(true)
                .takes_value(true))
            .arg(Arg::with_name("PUBLIC_DIR")
                .help("Directory to save ACME simple http challenge. This option is required.")
                .short("P")
                .long("public-dir")
                .takes_value(true))
            .arg(Arg::with_name("EMAIL")
                .help("Contact email address (optional).")
                .short("E")
                .long("email")
                .takes_value(true))
            .arg(Arg::with_name("DOMAIN_CSR")
                .help("Path to domain certificate signing request.")
                .short("C")
                .long("domain-csr")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_USER_KEY")
                .help("Path to save private user key.")
                .long("save-user-key")
                .short("u")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_DOMAIN_KEY")
                .help("Path to save domain private key.")
                .short("k")
                .long("save-domain-key")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_DOMAIN_CSR")
                .help("Path to save domain certificate signing request.")
                .long("save-csr")
                .short("S")
                .takes_value(true))
            .arg(Arg::with_name("SAVE_SIGNED_CERTIFICATE")
                .help("Path to save signed certificate. Default is STDOUT.")
                .short("o")
                .long("save-crt")
                .takes_value(true))
            .arg(Arg::with_name("CHAIN")
                .help("Chains the signed certificate with Let's Encrypt Authority X3 \
                       (IdenTrust cross-signed) intermediate certificate.")
                .short("c")
                .long("chain")
                .takes_value(false))
            .arg(Arg::with_name("DNS_CHALLENGE")
                 .help("Use DNS challenge instead of HTTP. This option requires user \
                        to generate a TXT record for domain")
                 .short("d")
                 .long("dns")
                 .takes_value(false)))
        .subcommand(SubCommand::with_name("revoke")
            .about("Revokes a signed certificate")
            .display_order(2)
            .arg(Arg::with_name("USER_KEY")
                .help("User or domain private key path.")
                .long("user-key")
                .short("K")
                .required(true)
                .takes_value(true))
            .arg(Arg::with_name("SIGNED_CRT")
                .help("Path to signed domain certificate to revoke.")
                .long("signed-crt")
                .short("C")
                .required(true)
                .takes_value(true)))
        .arg(Arg::with_name("verbose")
             .help("Show verbose output")
             .short("v")
             .multiple(true))
        .get_matches();

    init_logger(matches.occurrences_of("verbose"));

    let res = if let Some(matches) = matches.subcommand_matches("sign") {
        sign_certificate(matches)
    } else if let Some(matches) = matches.subcommand_matches("revoke") {
        revoke_certificate(matches)
    } else {
        println!("{}", matches.usage());
        Ok(())
    };

    if let Err(e) = res {
        eprintln!("{}", e);
        ::std::process::exit(1);
    }
}

fn sign_certificate(matches: &ArgMatches) -> Result<()> {
    // get domain names from --domain-csr or --domain arguments
    // FIXME: there is so many unncessary string conversations in the following code
    let domains: Vec<String> = if let Some(csr_path) = matches.value_of("DOMAIN_CSR") {
        names_from_csr(csr_path)?.into_iter().collect()
    } else {
        matches.values_of("DOMAIN")
            .ok_or("You need to provide at least one domain name")?.map(|s| s.to_owned()).collect()
    };

    // domains could be empty if provided --csr doesn't contain any
    if domains.is_empty() {
        return Err("You need to provide at least one domain name with --domain argument \
                   or from --csr".into());
    }

    let directory = Directory::lets_encrypt()?;

    let mut account_registration = directory.account_registration();

    if let Some(email) = matches.value_of("EMAIL") {
        account_registration = account_registration.email(email);
    }

    if let Some(user_key_path) = matches.value_of("USER_KEY_PATH") {
        account_registration = account_registration.pkey_from_file(user_key_path)?;
    }

    let account = account_registration.register()?;

    for domain in &domains {
        let authorization = account.authorization(domain)?;
        if !matches.is_present("DNS_CHALLENGE") {
            let challenge = authorization.get_http_challenge().ok_or("HTTP challenge not found")?;
            challenge.save_key_authorization(matches.value_of("PUBLIC_DIR")
                                                 .ok_or("--public-dir not defined. \
                                                            You need to define a public \
                                                            directory to use http challenge \
                                                            verification")?)?;
            challenge.validate()?;
        } else {
            let challenge = authorization.get_dns_challenge().ok_or("DNS challenge not found")?;
            println!("Please create a TXT record for _acme-challenge.{}: {}\n\
                      Press enter to continue",
                     domain,
                     challenge.signature()?);
            io::stdin().read_line(&mut String::new()).unwrap();
            challenge.validate()?;
        }
    }

    let dv: Vec<&str> = domains.iter().map(String::as_str).collect();
    let mut certificate_signer = account.certificate_signer(dv.as_slice());

    if let Some(domain_key_path) = matches.value_of("DOMAIN_KEY_PATH") {
        if let Some(csr_path) = matches.value_of("DOMAIN_CSR") {
            certificate_signer = certificate_signer.csr_from_file(domain_key_path, csr_path)?;
        } else {
            certificate_signer = certificate_signer.pkey_from_file(domain_key_path)?;
        }
    }

    let certificate = certificate_signer.sign_certificate()?;
    let signed_certificate_path = matches.value_of("SAVE_SIGNED_CERTIFICATE")
        .ok_or("You need to save signed certificate")?;
    if matches.is_present("CHAIN") {
        certificate.save_signed_certificate_and_chain(None, signed_certificate_path)?;
    } else {
        certificate.save_signed_certificate(signed_certificate_path)?;
    }

    if let Some(path) = matches.value_of("SAVE_DOMAIN_KEY") {
        certificate.save_private_key(path)?;
    }
    if let Some(path) = matches.value_of("SAVE_DOMAIN_CSR") {
        certificate.save_csr(path)?;
    }
    if let Some(path) = matches.value_of("SAVE_USER_KEY") {
        account.save_private_key(path)?;
    }

    Ok(())
}

fn revoke_certificate(matches: &ArgMatches) -> Result<()> {
    let directory = Directory::lets_encrypt()?;
    let account = directory.account_registration()
        .pkey_from_file(matches.value_of("USER_KEY")
                            .ok_or("You need to provide user \
                                   or domain private key used \
                                   to sign certificate.")?)?
        .register()?;
    account.revoke_certificate_from_file(matches.value_of("SIGNED_CRT")
                                             .ok_or("You need to provide \
                                                    a signed certificate to \
                                                    revoke.")?)?;
    Ok(())
}

fn init_logger(level: u64) {
    let level = match level {
        0 => "",
        1 => "acme_client=info",
        _ => "acme_client=debug",
    };
    let mut builder = env_logger::LogBuilder::new();
    builder.parse(&::std::env::var("RUST_LOG").unwrap_or(level.to_owned()));
    let _ = builder.init();
}

fn names_from_csr<P: AsRef<Path>>(csr_path: P) -> Result<HashSet<String>> {
    use std::fs::File;
    use std::io::Read;
    use std::slice;
    use openssl::x509::{X509Req, X509Extension};
    use openssl::nid;
    use openssl::stack::Stack;
    use openssl::types::OpenSslTypeRef;
    use std::os::raw::{c_int, c_long, c_uchar};
    use openssl::types::OpenSslType;

    fn read_file<P: AsRef<Path>>(path: P) -> Result<Vec<u8>> {
        let mut file = File::open(path)?;
        let mut content = Vec::new();
        file.read_to_end(&mut content)?;
        Ok(content)
    }

    let csr = X509Req::from_pem(&read_file(csr_path)?)?;

    let mut names = HashSet::new();

    // add CN to names first
    if let Some(cn) = csr.subject_name().entries_by_nid(nid::COMMONNAME).nth(0) {
        names.insert(String::from_utf8_lossy(cn.data().as_slice()).into_owned());
    }

    unsafe {
        #[repr(C)]
        struct Asn1StringSt {
            length: c_int,
            type_: c_int,
            data: *mut c_uchar,
            flags: c_long
        }
        extern "C" {
            fn X509_REQ_get_extensions(
                req: *mut openssl_sys::X509_REQ
            ) -> *mut openssl_sys::stack_st_X509_EXTENSION;
            fn X509v3_get_ext_by_NID(
                x: *const openssl_sys::stack_st_X509_EXTENSION,
                nid: c_int,
                lastpos: c_int
            ) -> c_int;
            fn X509_EXTENSION_get_data(
                ne: *mut openssl_sys::X509_EXTENSION,
            ) -> *mut Asn1StringSt;
        }
        let extensions = X509_REQ_get_extensions(csr.as_ptr());
        if !extensions.is_null() {
            let san_extension_idx = X509v3_get_ext_by_NID(extensions,
                                                          openssl_sys::NID_subject_alt_name,
                                                          -1);
            if let Some(san_extension) = Stack::<X509Extension>::from_ptr(extensions)
                .iter().nth(san_extension_idx as usize) {

                let extension_data = X509_EXTENSION_get_data(san_extension.as_ptr());
                let slc = slice::from_raw_parts((*extension_data).data,
                                                (*extension_data).length as usize);
                parse_asn1_octet_str(slc).iter().for_each(|n| {
                    names.insert(n.to_string());
                });
            }
        }
    }

    Ok(names)
}

fn parse_asn1_octet_str(s: &[u8]) -> Vec<String> {
    let mut iter = s.split(|n| *n == 130);
    let mut names = Vec::new();
    if iter.next().is_some() {
        for s in iter {
            let mut v = s.to_vec();
            v.remove(0); // remove first element which is length
            let name = String::from_utf8_lossy(&v);
            names.push(name.into_owned());
        }
    }
    names
}

#[test]
fn test_names_from_csr() {
    let _ = env_logger::init();
    let mut names = HashSet::new();
    names.insert("cn.example.com".to_owned());
    names.insert("www.example.com".to_owned());
    names.insert("example.com".to_owned());
    let names_from_csr = names_from_csr("tests/domain_with_san.csr").unwrap();
    assert_eq!(names, names_from_csr);
}
<|endoftext|>


<commit_before>extern crate getopts;

use getopts::Options;
use std::env;
use std::io::{self, Write};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, TcpStream};
use std::str::FromStr;
use std::sync::mpsc::{Sender, channel};
use std::thread;

// Max possible port
const MAX: u16 = 65535;

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("j",
                "",
                "number of threads to use for concurrent scanning",
                "THREADS");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            println!("error parsing options: {}", e.to_string());
            return;
        }
    };

    // Present usage if '-h' or no IP address provided
    if matches.opt_present("h") || matches.free.is_empty() {
        let brief = format!("Usage: {} -j THREADS IPADDR", program);
        print!("{}", opts.usage(&brief));
        return;
    }

    // Default to 4 threads, but allow user to specify more or less
    let num_threads = match matches.opt_str("j") {
        Some(j) => j.parse().expect("flag '-j' must be an integer"),
        None => 4,
    };

    // Parse IPv4 or IPv6 address for scanning
    let addr = IpAddr::from_str(&matches.free[0]).unwrap();

    // Send and receive results via channels of port numbers, scanning
    // concurrently using threads
    let (tx, rx) = channel::<u16>();
    for i in 0..num_threads {
        let tx = tx.clone();

        thread::spawn(move || {
            scan(tx, i, addr, num_threads);
        });
    }

    // Drop transmit side of channel in main thread so that for loop
    // will end once all worker threads complete
    let mut out = vec![];
    drop(tx);
    for port in rx {
        out.push(port);
    }

    // Add newline after progress, sort vector and print all ports
    println!("");
    out.sort();
    for v in out {
        println!("{} is open", v);
    }
}

// scan scans ports at an IP address and sends any open ports it finds back on its
// channel.  scan exits once MAX has been reached.
fn scan(tx: Sender<u16>, start_port: u16, addr: IpAddr, num_threads: u16) {
    let mut port: u16 = start_port + 1;

    loop {
        match TcpStream::connect((addr, port)) {
            Ok(_) => {
                // Found open port, indicate progress and send to main thread
                print!(".");
                io::stdout().flush().unwrap();
                tx.send(port).unwrap();
            }
            Err(_) => {}
        }

        // Break loop when out of ports
        if (MAX - port) <= num_threads {
            break;
        }

        port += num_threads;
    }
}
<commit_msg>main: improvements from Rust meetup code review<commit_after>extern crate getopts;

use getopts::Options;
use std::env;
use std::io::{self, Write};
use std::net::{IpAddr, TcpStream};
use std::str::FromStr;
use std::sync::mpsc::{Sender, channel};
use std::thread;

// Max possible port
const MAX: u16 = 65535;

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("j",
                "",
                "number of threads to use for concurrent scanning",
                "THREADS");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(e) => {
            println!("error parsing options: {}", e.to_string());
            return;
        }
    };

    // Present usage if '-h' or no IP address provided
    if matches.opt_present("h") || matches.free.is_empty() {
        let brief = format!("Usage: {} -j THREADS IPADDR", program);
        print!("{}", opts.usage(&brief));
        return;
    }

    // Default to 4 threads, but allow user to specify more or less
    let num_threads = match matches.opt_str("j") {
        Some(j) => j.parse().expect("flag '-j' must be an integer"),
        None => 4,
    };

    // Parse IPv4 or IPv6 address for scanning
    let addr = IpAddr::from_str(&matches.free[0])
        .expect("IPADDR must be a valid IPv4 or IPv6 address");

    // Send and receive results via channels of port numbers, scanning
    // concurrently using threads
    let (tx, rx) = channel();
    for i in 0..num_threads {
        let tx = tx.clone();

        thread::spawn(move || {
            scan(tx, i, addr, num_threads);
        });
    }

    // Drop transmit side of channel in main thread so that for loop
    // will end once all worker threads complete
    let mut out = vec![];
    drop(tx);
    for port in rx {
        out.push(port);
    }

    // Add newline after progress, sort vector and print all ports
    println!("");
    out.sort();
    for v in out {
        println!("{} is open", v);
    }
}

// scan scans ports at an IP address and sends any open ports it finds back on its
// channel.  scan exits once MAX has been reached.
fn scan(tx: Sender<u16>, start_port: u16, addr: IpAddr, num_threads: u16) {
    let mut port: u16 = start_port + 1;

    loop {
        match TcpStream::connect((addr, port)) {
            Ok(_) => {
                // Found open port, indicate progress and send to main thread
                print!(".");
                io::stdout().flush().unwrap();
                tx.send(port).unwrap();
            }
            Err(_) => {}
        }

        // Break loop when out of ports
        if (MAX - port) <= num_threads {
            break;
        }

        port += num_threads;
    }
}
<|endoftext|>