<commit_before>extern crate redis;
use std::error::Error;
use redis::{Commands, PipelineCommands, transaction};

use std::collections::HashMap;

/// This function demonstrates how a return value can be coerced into a
/// hashmap of tuples.  This is particularly useful for responses like
/// CONFIG GET or all most H functions which will return responses in
/// such list of implied tuples.
fn do_print_max_entry_limits(con: &redis::Connection) -> redis::RedisResult<()> {
    // since rust cannot know what format we actually want we need to be
    // explicit here and define the type of our response.  In this case
    // String -> int fits all the items we query for.
    let config : HashMap<String, int> = try!(
        redis::cmd("CONFIG").arg("GET").arg("*-max-*-entries").query(con));

    println!("Max entry limits:");

    // because our HashSet stores keys as actual strings we cannot use
    // the find method because of a type mismatch (it takes strings and
    // not slices).  We can however avoid the allocation we can use the
    // find_equiv method.
    println!("  max-intset:        {}", config.find_equiv(
        "set-max-intset-entries").unwrap_or(&0));
    println!("  hash-max-ziplist:  {}", config.find_equiv
        ("hash-max-ziplist-entries").unwrap_or(&0));
    println!("  list-max-ziplist:  {}", config.find_equiv(
        "list-max-ziplist-entries").unwrap_or(&0));
    println!("  zset-max-ziplist:  {}", config.find_equiv(
        "zset-max-ziplist-entries").unwrap_or(&0));

    Ok(())
}

/// This is a pretty stupid example that demonstrates how to create a large
/// set through a pipeline and how to iterate over it through implied
/// cursors.
fn do_show_scanning(con: &redis::Connection) -> redis::RedisResult<()> {
    // This makes a large pipeline of commands.  Because the pipeline is
    // modified in place we can just ignore the return value upon the end
    // of each iteration.
    let mut pipe = redis::pipe();
    for num in range(0, 1000u) {
        pipe.cmd("SADD").arg("my_set").arg(num).ignore();
    }

    // since we don't care about the return value of the pipeline we can
    // just cast it into the unit type.
    let _ : () = try!(pipe.query(con));

    // since rust currently does not track temporaries for us, we need to
    // store it in a local variable.
    let mut cmd = redis::cmd("SSCAN");
    cmd.arg("my_set").cursor_arg(0);

    // as a simple exercise we just sum up the iterator.  Since the fold
    // method carries an initial value we do not need to define the
    // type of the iterator, rust will figure "int" out for us.
    let sum = try!(cmd.iter(con)).fold(0i, |a, b| a + b);

    println!("The sum of all numbers in the set 0-1000: {}", sum);

    Ok(())
}

/// Demonstrates how to do an atomic increment in a very low level way.
fn do_atomic_increment_lowlevel(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run low-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(redis::cmd("SET").arg(key).arg(42i).query(con));

    loop {
        // we need to start watching the key we care about, so that our
        // exec fails if the key changes.
        let _ : () = try!(redis::cmd("WATCH").arg(key).query(con));

        // load the old value, so we know what to increment.
        let val : int = try!(redis::cmd("GET").arg(key).query(con));

        // at this point we can go into an atomic pipe (a multi block)
        // and set up the keys.
        let response : Option<(int,)> = try!(redis::pipe()
            .atomic()
            .cmd("SET").arg(key).arg(val + 1).ignore()
            .cmd("GET").arg(key)
            .query(con));

        match response {
            None => { continue; }
            Some(response) => {
                let (new_val,) = response;
                println!("  New value: {}", new_val);
                break;
            }
        }
    }

    Ok(())
}

/// Demonstrates how to do an atomic increment with transaction support.
fn do_atomic_increment(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run high-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(con.set(key, 42i));

    // run the transaction block.
    let (new_val,) : (int,) = transaction(con, [key].as_slice(), |pipe| {
        // load the old value, so we know what to increment.
        let val : int = try!(con.get(key));
        // increment
        pipe
            .set(key, val + 1).ignore()
            .get(key).query(con)
    }).unwrap();

    // and print the result
    println!("New value: {}", new_val);

    Ok(())
}

/// Runs all the examples and propagates errors up.
fn do_redis_code() -> redis::RedisResult<()>
{
    // general connection handling
    let client = try!(redis::Client::open("redis://127.0.0.1:1234/"));
    let con = try!(client.get_connection());

    // read some config and print it.
    try!(do_print_max_entry_limits(&con));

    // demonstrate how scanning works.
    try!(do_show_scanning(&con));

    // shows an atomic increment.
    try!(do_atomic_increment_lowlevel(&con));
    try!(do_atomic_increment(&con));

    Ok(())
}

fn main()
{
    // at this point the errors are fatal, let's just fail hard.
    match do_redis_code() {
        Err(err) => {
            println!("Could not execute example:");
            println!("  {}: {}", err.category(), err.description());
            match err.detail() {
                Some(msg) => println!("  Detail: {}", msg),
                None => {}
            };
        },
        Ok(()) => {},
    }
}
<commit_msg>Fixed port of example<commit_after>extern crate redis;
use std::error::Error;
use redis::{Commands, PipelineCommands, transaction};

use std::collections::HashMap;

/// This function demonstrates how a return value can be coerced into a
/// hashmap of tuples.  This is particularly useful for responses like
/// CONFIG GET or all most H functions which will return responses in
/// such list of implied tuples.
fn do_print_max_entry_limits(con: &redis::Connection) -> redis::RedisResult<()> {
    // since rust cannot know what format we actually want we need to be
    // explicit here and define the type of our response.  In this case
    // String -> int fits all the items we query for.
    let config : HashMap<String, int> = try!(
        redis::cmd("CONFIG").arg("GET").arg("*-max-*-entries").query(con));

    println!("Max entry limits:");

    // because our HashSet stores keys as actual strings we cannot use
    // the find method because of a type mismatch (it takes strings and
    // not slices).  We can however avoid the allocation we can use the
    // find_equiv method.
    println!("  max-intset:        {}", config.find_equiv(
        "set-max-intset-entries").unwrap_or(&0));
    println!("  hash-max-ziplist:  {}", config.find_equiv
        ("hash-max-ziplist-entries").unwrap_or(&0));
    println!("  list-max-ziplist:  {}", config.find_equiv(
        "list-max-ziplist-entries").unwrap_or(&0));
    println!("  zset-max-ziplist:  {}", config.find_equiv(
        "zset-max-ziplist-entries").unwrap_or(&0));

    Ok(())
}

/// This is a pretty stupid example that demonstrates how to create a large
/// set through a pipeline and how to iterate over it through implied
/// cursors.
fn do_show_scanning(con: &redis::Connection) -> redis::RedisResult<()> {
    // This makes a large pipeline of commands.  Because the pipeline is
    // modified in place we can just ignore the return value upon the end
    // of each iteration.
    let mut pipe = redis::pipe();
    for num in range(0, 1000u) {
        pipe.cmd("SADD").arg("my_set").arg(num).ignore();
    }

    // since we don't care about the return value of the pipeline we can
    // just cast it into the unit type.
    let _ : () = try!(pipe.query(con));

    // since rust currently does not track temporaries for us, we need to
    // store it in a local variable.
    let mut cmd = redis::cmd("SSCAN");
    cmd.arg("my_set").cursor_arg(0);

    // as a simple exercise we just sum up the iterator.  Since the fold
    // method carries an initial value we do not need to define the
    // type of the iterator, rust will figure "int" out for us.
    let sum = try!(cmd.iter(con)).fold(0i, |a, b| a + b);

    println!("The sum of all numbers in the set 0-1000: {}", sum);

    Ok(())
}

/// Demonstrates how to do an atomic increment in a very low level way.
fn do_atomic_increment_lowlevel(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run low-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(redis::cmd("SET").arg(key).arg(42i).query(con));

    loop {
        // we need to start watching the key we care about, so that our
        // exec fails if the key changes.
        let _ : () = try!(redis::cmd("WATCH").arg(key).query(con));

        // load the old value, so we know what to increment.
        let val : int = try!(redis::cmd("GET").arg(key).query(con));

        // at this point we can go into an atomic pipe (a multi block)
        // and set up the keys.
        let response : Option<(int,)> = try!(redis::pipe()
            .atomic()
            .cmd("SET").arg(key).arg(val + 1).ignore()
            .cmd("GET").arg(key)
            .query(con));

        match response {
            None => { continue; }
            Some(response) => {
                let (new_val,) = response;
                println!("  New value: {}", new_val);
                break;
            }
        }
    }

    Ok(())
}

/// Demonstrates how to do an atomic increment with transaction support.
fn do_atomic_increment(con: &redis::Connection) -> redis::RedisResult<()> {
    let key = "the_key";
    println!("Run high-level atomic increment:");

    // set the initial value so we have something to test with.
    let _ : () = try!(con.set(key, 42i));

    // run the transaction block.
    let (new_val,) : (int,) = transaction(con, [key].as_slice(), |pipe| {
        // load the old value, so we know what to increment.
        let val : int = try!(con.get(key));
        // increment
        pipe
            .set(key, val + 1).ignore()
            .get(key).query(con)
    }).unwrap();

    // and print the result
    println!("New value: {}", new_val);

    Ok(())
}

/// Runs all the examples and propagates errors up.
fn do_redis_code() -> redis::RedisResult<()>
{
    // general connection handling
    let client = try!(redis::Client::open("redis://127.0.0.1/"));
    let con = try!(client.get_connection());

    // read some config and print it.
    try!(do_print_max_entry_limits(&con));

    // demonstrate how scanning works.
    try!(do_show_scanning(&con));

    // shows an atomic increment.
    try!(do_atomic_increment_lowlevel(&con));
    try!(do_atomic_increment(&con));

    Ok(())
}

fn main()
{
    // at this point the errors are fatal, let's just fail hard.
    match do_redis_code() {
        Err(err) => {
            println!("Could not execute example:");
            println!("  {}: {}", err.category(), err.description());
            match err.detail() {
                Some(msg) => println!("  Detail: {}", msg),
                None => {}
            };
        },
        Ok(()) => {},
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use conrod::{
    Background,
    Color,
    Colorable,
    Frameable,
    Labelable,
    Positionable,
    Sizeable,
    Theme,
    Toggle,
    Ui,
    Widget,
};
use conrod::color::{black, grayscale, green, red};
use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;
type RcGraphics = Rc<RefCell<GlGraphics>>;
type RcUi = Rc<RefCell<Ui<GlyphCache<'static>>>>;

struct App {
    window: RcWindow,
    graphics: RcGraphics,
    ui: RcUi,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: Color
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(self.window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();
        let ui = &mut *self.ui.borrow_mut();
        let mut rebind = self.translator.clone().into_rebind();

        // declare widget ids
        widget_ids! {
            X_INVERT_TOGGLE,
            Y_INVERT_TOGGLE
        }

        // draw the ui
        gl_graphics.draw(args.viewport(), |c, gl| {
            Background::new().color(self.bg_color).set(ui);

            Toggle::new(rebind.get_x_motion_inverted())
                .xy(-350.0, 260.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert x".to_string())
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_x_motion_inverted(b))
                .set(X_INVERT_TOGGLE, ui);

            Toggle::new(rebind.get_y_motion_inverted())
                .xy(-350.0, 200.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert y".to_string())
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_y_motion_inverted(b))
                .set(Y_INVERT_TOGGLE, ui);

            ui.draw(c, gl)
        });

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color.to_fsa(),
                                                                square,
                                                                c.transform,
                                                                gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color.to_fsa(),
                                                              dot,
                                                              c.transform,
                                                              gl));
        }

        self.translator = rebind.into();
    }
}

struct Character {
    color: Color,
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: Color, tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: Color,
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: green(),
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("calaxite", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .ok()
        .expect("Could not create main window");

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = {
        const INITIAL_CHARACTER_POS: [f64; 2] = [WINDOW_SIZE.0 as f64 / 20.0,
                                                 WINDOW_SIZE.1 as f64 * 0.85];
        Character::new(red(), INITIAL_CHARACTER_POS, 50.0)
    };

    let ui = {
        let glyph_cache = {
            let font_path = find_folder::Search::ParentsThenKids(3, 3)
                .for_folder("assets")
                .ok()
                .expect("Could not find assets folder")
                .join("fonts/NotoSans/NotoSans-Regular.ttf");

            GlyphCache::new(&font_path)
                .ok()
                .expect("Could not find font file within assets folder")
        };

        Ui::new(glyph_cache, Theme::default())
    };

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        ui: Rc::new(RefCell::new(ui)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: black()
    };

    for e in app.window.clone().events() {
        app.ui.borrow_mut().handle_event(&e);
        match e {
            Event::Input(i) => { app.input(&i); },
            Event::Update(u) => { app.update(&u); },
            Event::Render(r) => { app.render(&r); },
            _ => { }
        }
    }
}<commit_msg>Give the window a more relevant title<commit_after>#[macro_use] extern crate conrod;
extern crate find_folder;
extern crate glutin_window;
extern crate graphics;
extern crate rebind;
extern crate piston;
extern crate opengl_graphics;
extern crate viewport;

use conrod::{
    Background,
    Color,
    Colorable,
    Frameable,
    Labelable,
    Positionable,
    Sizeable,
    Theme,
    Toggle,
    Ui,
    Widget,
};
use conrod::color::{black, grayscale, green, red};
use glutin_window::GlutinWindow;
use graphics::*;
use opengl_graphics::{GlGraphics, OpenGL};
use opengl_graphics::glyph_cache::GlyphCache;
use piston::event_loop::{EventMap, Events};
use piston::input::{
    Event,
    Input,
    Motion,
    RenderArgs,
    RenderEvent,
    UpdateArgs,
    UpdateEvent
};
use piston::input::keyboard::Key;
use piston::input::Button::Keyboard;
use piston::window::{Window, WindowSettings};
use rebind::{Action, InputTranslator, RebindBuilder, Translated};
use std::cell::RefCell;
use std::rc::Rc;

type RcWindow = Rc<RefCell<GlutinWindow>>;
type RcGraphics = Rc<RefCell<GlGraphics>>;
type RcUi = Rc<RefCell<Ui<GlyphCache<'static>>>>;

struct App {
    window: RcWindow,
    graphics: RcGraphics,
    ui: RcUi,
    translator: InputTranslator<CharacterAction>,
    character: Character,
    cursor: VirtualCursor,
    bg_color: Color
}

impl App {
    fn input(&mut self, input: &Input) {
        if let Some(t) = self.translator.translate(input) {
            match t {
                Translated::Press(action) => {
                    const CHARACTER_WALK_SPEED_INCREMENT: f64 = 400.0;
                    match action {
                        CharacterAction::Jump => {
                            println!("You jumped! Yay!");
                        },
                        CharacterAction::MoveLeft => {
                            if self.character.current_velocity[0] > (self.character.max_velocity[0] * -1.0) {
                                self.character.current_velocity[0] -= CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        },
                        CharacterAction::MoveRight => {
                            if self.character.current_velocity[0] < self.character.max_velocity[0] {
                                self.character.current_velocity[0] += CHARACTER_WALK_SPEED_INCREMENT;
                            }
                        }
                    }
                },
                Translated::Release(_) => {
                    self.character.current_velocity = [0.0, 0.0];
                },
                Translated::Move(Motion::MouseCursor(x, y)) => {
                    self.cursor.position = [x, y];
                },
                _ => { }
            }
        }
    }

    fn update(&mut self, args: &UpdateArgs) {
        // we need to pass the window to update (and set the size here) because using
        // the update event from the window events queue is currently broken.
        self.translator.set_size(self.window.borrow().size());

        // update the character's velocity
        let ctl = self.character.topleft;
        let v = self.character.current_velocity;

        self.character.topleft = [ctl[0] + (v[0] * args.dt), ctl[1] + (v[1] * args.dt)];
    }

    fn render(&mut self, args: &RenderArgs) {
        let mut gl_graphics = self.graphics.borrow_mut();
        let ui = &mut *self.ui.borrow_mut();
        let mut rebind = self.translator.clone().into_rebind();

        // declare widget ids
        widget_ids! {
            X_INVERT_TOGGLE,
            Y_INVERT_TOGGLE
        }

        // draw the ui
        gl_graphics.draw(args.viewport(), |c, gl| {
            Background::new().color(self.bg_color).set(ui);

            Toggle::new(rebind.get_x_motion_inverted())
                .xy(-350.0, 260.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert x".to_string())
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_x_motion_inverted(b))
                .set(X_INVERT_TOGGLE, ui);

            Toggle::new(rebind.get_y_motion_inverted())
                .xy(-350.0, 200.0)
                .dimensions(80.0, 40.0)
                .color(grayscale(0.4))
                .frame(1.0)
                .label(&"Invert y".to_string())
                .label_color(self.bg_color.plain_contrast())
                .label_font_size(16)
                .react(|b| rebind.set_y_motion_inverted(b))
                .set(Y_INVERT_TOGGLE, ui);

            ui.draw(c, gl)
        });

        // draw the character
        {
            let square = rectangle::square(self.character.topleft[0],
                                           self.character.topleft[1],
                                           self.character.size);

            gl_graphics.draw(args.viewport(), |c, gl| rectangle(self.character.color.to_fsa(),
                                                                square,
                                                                c.transform,
                                                                gl));
        }

        // draw the cursor dot
        {
            let dot = ellipse::circle(self.cursor.position[0],
                                      self.cursor.position[1],
                                      self.cursor.size);
            gl_graphics.draw(args.viewport(), |c, gl| ellipse(self.cursor.color.to_fsa(),
                                                              dot,
                                                              c.transform,
                                                              gl));
        }

        self.translator = rebind.into();
    }
}

struct Character {
    color: Color,
    topleft: [f64; 2],
    current_velocity: [f64; 2],
    max_velocity: [f64; 2],
    size: f64
}

impl Character {
    fn new(col: Color, tl: [f64; 2], sz: f64) -> Self {
        Character {
            color: col,
            topleft: tl,
            current_velocity: [0.0, 0.0],
            max_velocity: [800.0, 0.0],
            size: sz
        }
    }
}

struct VirtualCursor {
    position: [f64; 2],
    color: Color,
    size: f64
}

impl VirtualCursor {
    fn new() -> Self {
        VirtualCursor {
            position: [0.0, 0.0],
            color: green(),
            size: 5.0
        }
    }
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
enum CharacterAction {
    Jump,
    MoveLeft,
    MoveRight
}

impl Action for CharacterAction { }

fn main() {
    const OPENGL: OpenGL = OpenGL::V3_2;
    const WINDOW_SIZE: (u32, u32) = (800, 600);

    let window = WindowSettings::new("rebind-example", WINDOW_SIZE)
        .exit_on_esc(true)
        .fullscreen(false)
        .opengl(OPENGL)
        .vsync(true)
        .build()
        .ok()
        .expect("Could not create main window");

    let gl_graphics = GlGraphics::new(OPENGL);

    let translator = RebindBuilder::new(WINDOW_SIZE)
        .with_action_mapping(Keyboard(Key::Space), CharacterAction::Jump)
        .with_action_mapping(Keyboard(Key::Left),  CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::A),     CharacterAction::MoveLeft)
        .with_action_mapping(Keyboard(Key::Right), CharacterAction::MoveRight)
        .with_action_mapping(Keyboard(Key::D),     CharacterAction::MoveRight)
        .build_translator();

    let character = {
        const INITIAL_CHARACTER_POS: [f64; 2] = [WINDOW_SIZE.0 as f64 / 20.0,
                                                 WINDOW_SIZE.1 as f64 * 0.85];
        Character::new(red(), INITIAL_CHARACTER_POS, 50.0)
    };

    let ui = {
        let glyph_cache = {
            let font_path = find_folder::Search::ParentsThenKids(3, 3)
                .for_folder("assets")
                .ok()
                .expect("Could not find assets folder")
                .join("fonts/NotoSans/NotoSans-Regular.ttf");

            GlyphCache::new(&font_path)
                .ok()
                .expect("Could not find font file within assets folder")
        };

        Ui::new(glyph_cache, Theme::default())
    };

    let mut app = App {
        window: Rc::new(RefCell::new(window)),
        graphics: Rc::new(RefCell::new(gl_graphics)),
        ui: Rc::new(RefCell::new(ui)),
        translator: translator,
        character: character,
        cursor: VirtualCursor::new(),
        bg_color: black()
    };

    for e in app.window.clone().events() {
        app.ui.borrow_mut().handle_event(&e);
        match e {
            Event::Input(i) => { app.input(&i); },
            Event::Update(u) => { app.update(&u); },
            Event::Render(r) => { app.render(&r); },
            _ => { }
        }
    }
}<|endoftext|>


<commit_before><commit_msg>Typo fix<commit_after><|endoftext|>


<commit_before>use mac::{Mac, MacType};
use header::Header;
use credentials::Key;
use error::HawkError;

/// A Response represents a response from an HTTP server.
///
/// The structure is created from a request and then used to either create (server) or validate
/// (client) a `Server-Authentication` header.
///
/// Like `Request`, Responses are built with ResponseBuilders.
///
/// # Examples
///
/// See the documentation in the crate root for examples.
#[derive(Debug, Clone)]
pub struct Response<'a> {
    method: &'a str,
    host: &'a str,
    port: u16,
    path: &'a str,
    req_header: &'a Header,
    hash: Option<&'a [u8]>,
    ext: Option<&'a str>,
}

impl<'a> Response<'a> {
    /// Create a new Header for this response, based on the given request and request header
    pub fn make_header(&self, key: &Key) -> Result<Header, HawkError> {
        let mac;
        // TODO: use .ok_or here (but this is hard with `ref nonce`)
        if let Some(ts) = self.req_header.ts {
            if let Some(ref nonce) = self.req_header.nonce {
                mac = Mac::new(MacType::Response,
                               key,
                               ts,
                               nonce,
                               self.method,
                               self.host,
                               self.port,
                               self.path,
                               self.hash,
                               self.ext)?;
            } else {
                return Err(HawkError::MissingAttributes);
            }
        } else {
            return Err(HawkError::MissingAttributes);
        }

        // Per JS implementation, the Server-Authorization header includes only mac, hash, and ext
        Header::new(None,
                    None,
                    None,
                    Some(mac),
                    match self.ext {
                        None => None,
                        Some(v) => Some(v.to_string()),
                    },
                    match self.hash {
                        None => None,
                        Some(v) => Some(v.to_vec()),
                    },
                    None,
                    None)
    }

    /// Validate a Server-Authorization header.
    ///
    /// This checks that the MAC matches and, if a hash has been supplied locally,
    /// checks that one was provided from the server and that it, too, matches.
    pub fn validate_header(&self, response_header: &Header, key: &Key) -> bool {
        // extract required fields, returning early if they are not present
        let ts = match self.req_header.ts {
            Some(ts) => ts,
            None => {
                return false;
            }
        };
        let nonce = match self.req_header.nonce {
            Some(ref nonce) => nonce,
            None => {
                return false;
            }
        };
        let header_mac = match response_header.mac {
            Some(ref mac) => mac,
            None => {
                return false;
            }
        };
        let header_ext = match response_header.ext {
            Some(ref ext) => Some(&ext[..]),
            None => None,
        };
        let header_hash = match response_header.hash {
            Some(ref hash) => Some(&hash[..]),
            None => None,
        };

        // first verify the MAC
        match Mac::new(MacType::Response,
                       key,
                       ts,
                       nonce,
                       self.method,
                       self.host,
                       self.port,
                       self.path,
                       header_hash,
                       header_ext) {
            Ok(calculated_mac) => {
                if &calculated_mac != header_mac {
                    return false;
                }
            }
            Err(_) => {
                return false;
            }
        };

        // ..then the hashes
        if let Some(local_hash) = self.hash {
            if let Some(server_hash) = header_hash {
                if local_hash != server_hash {
                    return false;
                }
            } else {
                return false;
            }
        }

        // NOTE: the timestamp self.req_header.ts was generated locally, so
        // there is no need to verify it

        true
    }
}

#[derive(Debug, Clone)]
pub struct ResponseBuilder<'a>(Response<'a>);

impl<'a> ResponseBuilder<'a> {
    /// Generate a new Response from a request header.
    ///
    /// This is more commonly accessed through `Request::make_response`.
    pub fn from_request_header(req_header: &'a Header,
                               method: &'a str,
                               host: &'a str,
                               port: u16,
                               path: &'a str)
                               -> Self {
        ResponseBuilder(Response {
                            method: method,
                            host: host,
                            port: port,
                            path: path,
                            req_header: req_header,
                            hash: None,
                            ext: None,
                        })
    }

    /// Set the content hash for the response.
    ///
    /// This should always be calculated from the response payload, not copied from a header.
    pub fn hash(mut self, hash: &'a [u8]) -> Self {
        // TODO: use into
        self.0.hash = Some(hash);
        self
    }

    /// Set the `ext` Hawk property for the response.
    ///
    /// This need only be set on the server; it is ignored in validating responses on the client.
    pub fn ext(mut self, ext: &'a str) -> Self {
        // TODO: use into
        self.0.ext = Some(ext);
        self
    }

    /// Get the response from this builder
    pub fn response(self) -> Response<'a> {
        self.0
    }
}

#[cfg(test)]
mod test {
    use super::ResponseBuilder;
    use header::Header;
    use credentials::Key;
    use mac::Mac;
    use time::Timespec;
    use ring::digest;

    fn make_req_header() -> Header {
        Header::new(None,
                    Some(Timespec::new(1353832234, 0)),
                    Some("j4h3g2"),
                    None,
                    None,
                    None,
                    None,
                    None)
                .unwrap()
    }

    #[test]
    fn test_validation_no_hash() {
        let req_header = make_req_header();
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .response();
        let mac: Mac = Mac::from(vec![48, 133, 228, 163, 224, 197, 222, 77, 117, 81, 143, 73, 71,
                                      120, 68, 238, 228, 40, 55, 64, 190, 73, 102, 123, 79, 185,
                                      199, 26, 62, 1, 137, 170]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        None,
                                        None,
                                        None)
                .unwrap();
        assert!(resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }

    #[test]
    fn test_validation_hash_in_header() {
        // When a hash is provided in the response header, but no hash is added to the Response,
        // it is ignored (so validation succeeds)
        let req_header = make_req_header();
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .response();
        let mac: Mac = Mac::from(vec![33, 147, 159, 211, 184, 194, 189, 74, 53, 229, 241, 161,
                                      215, 145, 22, 34, 206, 207, 242, 100, 33, 193, 36, 96, 149,
                                      133, 180, 4, 132, 87, 207, 238]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        Some(vec![1, 2, 3, 4]),
                                        None,
                                        None)
                .unwrap();
        assert!(resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }

    #[test]
    fn test_validation_hash_required_but_not_given() {
        // When Response.hash is called, but no hash is in the hader, validation fails.
        let req_header = make_req_header();
        let hash = vec![1, 2, 3, 4];
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .hash(&hash[..])
                .response();
        let mac: Mac = Mac::from(vec![48, 133, 228, 163, 224, 197, 222, 77, 117, 81, 143, 73, 71,
                                      120, 68, 238, 228, 40, 55, 64, 190, 73, 102, 123, 79, 185,
                                      199, 26, 62, 1, 137, 170]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        None,
                                        None,
                                        None)
                .unwrap();
        assert!(!resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }

    #[test]
    fn test_validation_hash_validated() {
        // When a hash is provided in the response header and the Response.hash method is called,
        // the two must match
        let req_header = make_req_header();
        let hash = vec![1, 2, 3, 4];
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .hash(&hash[..])
                .response();
        let mac: Mac = Mac::from(vec![33, 147, 159, 211, 184, 194, 189, 74, 53, 229, 241, 161,
                                      215, 145, 22, 34, 206, 207, 242, 100, 33, 193, 36, 96, 149,
                                      133, 180, 4, 132, 87, 207, 238]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        Some(vec![1, 2, 3, 4]),
                                        None,
                                        None)
                .unwrap();
        assert!(resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));

        // a different supplied hash won't match..
        let hash = vec![99, 99, 99, 99];
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .hash(&hash[..])
                .response();
        assert!(!resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }
}
<commit_msg>use ok_or instead of if let<commit_after>use mac::{Mac, MacType};
use header::Header;
use credentials::Key;
use error::HawkError;

/// A Response represents a response from an HTTP server.
///
/// The structure is created from a request and then used to either create (server) or validate
/// (client) a `Server-Authentication` header.
///
/// Like `Request`, Responses are built with ResponseBuilders.
///
/// # Examples
///
/// See the documentation in the crate root for examples.
#[derive(Debug, Clone)]
pub struct Response<'a> {
    method: &'a str,
    host: &'a str,
    port: u16,
    path: &'a str,
    req_header: &'a Header,
    hash: Option<&'a [u8]>,
    ext: Option<&'a str>,
}

impl<'a> Response<'a> {
    /// Create a new Header for this response, based on the given request and request header
    pub fn make_header(&self, key: &Key) -> Result<Header, HawkError> {
        let mac;
        let ts = self.req_header.ts.ok_or(HawkError::MissingAttributes)?;
        let nonce = self.req_header
            .nonce
            .as_ref()
            .ok_or(HawkError::MissingAttributes)?;
        mac = Mac::new(MacType::Response,
                       key,
                       ts,
                       nonce,
                       self.method,
                       self.host,
                       self.port,
                       self.path,
                       self.hash,
                       self.ext)?;

        // Per JS implementation, the Server-Authorization header includes only mac, hash, and ext
        Header::new(None,
                    None,
                    None,
                    Some(mac),
                    match self.ext {
                        None => None,
                        Some(v) => Some(v.to_string()),
                    },
                    match self.hash {
                        None => None,
                        Some(v) => Some(v.to_vec()),
                    },
                    None,
                    None)
    }

    /// Validate a Server-Authorization header.
    ///
    /// This checks that the MAC matches and, if a hash has been supplied locally,
    /// checks that one was provided from the server and that it, too, matches.
    pub fn validate_header(&self, response_header: &Header, key: &Key) -> bool {
        // extract required fields, returning early if they are not present
        let ts = match self.req_header.ts {
            Some(ts) => ts,
            None => {
                return false;
            }
        };
        let nonce = match self.req_header.nonce {
            Some(ref nonce) => nonce,
            None => {
                return false;
            }
        };
        let header_mac = match response_header.mac {
            Some(ref mac) => mac,
            None => {
                return false;
            }
        };
        let header_ext = match response_header.ext {
            Some(ref ext) => Some(&ext[..]),
            None => None,
        };
        let header_hash = match response_header.hash {
            Some(ref hash) => Some(&hash[..]),
            None => None,
        };

        // first verify the MAC
        match Mac::new(MacType::Response,
                       key,
                       ts,
                       nonce,
                       self.method,
                       self.host,
                       self.port,
                       self.path,
                       header_hash,
                       header_ext) {
            Ok(calculated_mac) => {
                if &calculated_mac != header_mac {
                    return false;
                }
            }
            Err(_) => {
                return false;
            }
        };

        // ..then the hashes
        if let Some(local_hash) = self.hash {
            if let Some(server_hash) = header_hash {
                if local_hash != server_hash {
                    return false;
                }
            } else {
                return false;
            }
        }

        // NOTE: the timestamp self.req_header.ts was generated locally, so
        // there is no need to verify it

        true
    }
}

#[derive(Debug, Clone)]
pub struct ResponseBuilder<'a>(Response<'a>);

impl<'a> ResponseBuilder<'a> {
    /// Generate a new Response from a request header.
    ///
    /// This is more commonly accessed through `Request::make_response`.
    pub fn from_request_header(req_header: &'a Header,
                               method: &'a str,
                               host: &'a str,
                               port: u16,
                               path: &'a str)
                               -> Self {
        ResponseBuilder(Response {
                            method: method,
                            host: host,
                            port: port,
                            path: path,
                            req_header: req_header,
                            hash: None,
                            ext: None,
                        })
    }

    /// Set the content hash for the response.
    ///
    /// This should always be calculated from the response payload, not copied from a header.
    pub fn hash(mut self, hash: &'a [u8]) -> Self {
        // TODO: use into
        self.0.hash = Some(hash);
        self
    }

    /// Set the `ext` Hawk property for the response.
    ///
    /// This need only be set on the server; it is ignored in validating responses on the client.
    pub fn ext(mut self, ext: &'a str) -> Self {
        // TODO: use into
        self.0.ext = Some(ext);
        self
    }

    /// Get the response from this builder
    pub fn response(self) -> Response<'a> {
        self.0
    }
}

#[cfg(test)]
mod test {
    use super::ResponseBuilder;
    use header::Header;
    use credentials::Key;
    use mac::Mac;
    use time::Timespec;
    use ring::digest;

    fn make_req_header() -> Header {
        Header::new(None,
                    Some(Timespec::new(1353832234, 0)),
                    Some("j4h3g2"),
                    None,
                    None,
                    None,
                    None,
                    None)
                .unwrap()
    }

    #[test]
    fn test_validation_no_hash() {
        let req_header = make_req_header();
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .response();
        let mac: Mac = Mac::from(vec![48, 133, 228, 163, 224, 197, 222, 77, 117, 81, 143, 73, 71,
                                      120, 68, 238, 228, 40, 55, 64, 190, 73, 102, 123, 79, 185,
                                      199, 26, 62, 1, 137, 170]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        None,
                                        None,
                                        None)
                .unwrap();
        assert!(resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }

    #[test]
    fn test_validation_hash_in_header() {
        // When a hash is provided in the response header, but no hash is added to the Response,
        // it is ignored (so validation succeeds)
        let req_header = make_req_header();
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .response();
        let mac: Mac = Mac::from(vec![33, 147, 159, 211, 184, 194, 189, 74, 53, 229, 241, 161,
                                      215, 145, 22, 34, 206, 207, 242, 100, 33, 193, 36, 96, 149,
                                      133, 180, 4, 132, 87, 207, 238]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        Some(vec![1, 2, 3, 4]),
                                        None,
                                        None)
                .unwrap();
        assert!(resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }

    #[test]
    fn test_validation_hash_required_but_not_given() {
        // When Response.hash is called, but no hash is in the hader, validation fails.
        let req_header = make_req_header();
        let hash = vec![1, 2, 3, 4];
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .hash(&hash[..])
                .response();
        let mac: Mac = Mac::from(vec![48, 133, 228, 163, 224, 197, 222, 77, 117, 81, 143, 73, 71,
                                      120, 68, 238, 228, 40, 55, 64, 190, 73, 102, 123, 79, 185,
                                      199, 26, 62, 1, 137, 170]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        None,
                                        None,
                                        None)
                .unwrap();
        assert!(!resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }

    #[test]
    fn test_validation_hash_validated() {
        // When a hash is provided in the response header and the Response.hash method is called,
        // the two must match
        let req_header = make_req_header();
        let hash = vec![1, 2, 3, 4];
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .hash(&hash[..])
                .response();
        let mac: Mac = Mac::from(vec![33, 147, 159, 211, 184, 194, 189, 74, 53, 229, 241, 161,
                                      215, 145, 22, 34, 206, 207, 242, 100, 33, 193, 36, 96, 149,
                                      133, 180, 4, 132, 87, 207, 238]);
        let server_header = Header::new(None,
                                        None,
                                        None,
                                        Some(mac),
                                        Some("server-ext"),
                                        Some(vec![1, 2, 3, 4]),
                                        None,
                                        None)
                .unwrap();
        assert!(resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));

        // a different supplied hash won't match..
        let hash = vec![99, 99, 99, 99];
        let resp =
            ResponseBuilder::from_request_header(&req_header, "POST", "localhost", 9988, "/a/b")
                .hash(&hash[..])
                .response();
        assert!(!resp.validate_header(&server_header, &Key::new("tok", &digest::SHA256)));
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio_core;
extern crate tokio_service;

use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use std::env;
use std::fs::{self, File};
use std::io;
use std::io::prelude::*;
use std::net;
use std::path::PathBuf;
use std::rc::Rc;
use std::str;
use std::sync::{Arc, Mutex, Once};
use std::thread;

use self::futures::sync::oneshot;
use self::futures::{Future, Stream};
use self::hyper::server::Http;
use self::tokio_core::net::TcpListener;
use self::tokio_core::reactor::Core;
use self::tokio_service::Service;
use curl::easy::{Easy, List};
use serde_json;

use models::NewUser;

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    iorx: Sink,
    quittx: Option<oneshot::Sender<()>>,
    #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
    thread: Option<thread::JoinHandle<Option<(Vec<u8>, PathBuf)>>>,
}

pub struct GhUser {
    pub login: &'static str,
    pub init: Once,
}

#[derive(Clone)]
struct Sink(Arc<Mutex<Vec<u8>>>);

impl<'a> Write for &'a Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for Bomb {
    fn drop(&mut self) {
        drop(self.quittx.take());
        let res = self.thread.take().unwrap().join();
        let stderr = str::from_utf8(&self.iorx.0.lock().unwrap())
            .unwrap()
            .to_string();
        match res {
            Err(..) if !thread::panicking() => panic!("server subtask failed: {}", stderr),
            Err(e) => if !stderr.is_empty() {
                println!("server subtask failed ({:?}): {}", e, stderr)
            },
            Ok(_) if thread::panicking() => {}
            Ok(None) => {}
            Ok(Some((data, file))) => {
                t!(t!(File::create(&file)).write_all(&data));
            }
        }
    }
}

fn cache_file(name: &str) -> PathBuf {
    PathBuf::from(file!())
        .parent()
        .unwrap()
        .join("http-data")
        .join(name)
}

enum Record {
    Capture(Vec<Exchange>, PathBuf),
    Replay(Vec<Exchange>),
}

pub fn proxy() -> (String, Bomb) {
    let me = thread::current().name().unwrap().to_string();
    let record = env::var("RECORD").is_ok();

    let a = t!(net::TcpListener::bind("127.0.0.1:0"));
    let ret = format!("http://{}", t!(a.local_addr()));

    let data = cache_file(&me.replace("::", "_"));
    let record = if record && !data.exists() {
        Record::Capture(Vec::new(), data)
    } else if !data.exists() {
        Record::Replay(serde_json::from_slice(b"[]").unwrap())
    } else {
        let mut body = Vec::new();
        t!(t!(File::open(&data)).read_to_end(&mut body));
        Record::Replay(serde_json::from_slice(&body).unwrap())
    };

    let sink = Arc::new(Mutex::new(Vec::new()));
    let sink2 = Sink(Arc::clone(&sink));

    let (quittx, quitrx) = oneshot::channel();

    let thread = thread::spawn(move || {
        let mut core = t!(Core::new());
        let handle = core.handle();
        let addr = t!(a.local_addr());
        let listener = t!(TcpListener::from_listener(a, &addr, &handle));
        let client = hyper::Client::configure()
            .connector(hyper_tls::HttpsConnector::new(4, &handle).unwrap())
            .build(&handle);

        let record = Rc::new(RefCell::new(record));
        let srv = listener.incoming().for_each(|(socket, _addr)| {
            let conn = Http::<hyper::Chunk>::new().serve_connection(
                socket,
                Proxy {
                    sink: sink2.clone(),
                    record: Rc::clone(&record),
                    client: client.clone(),
                },
            );

            let fut = conn.map(|_| ())
                .map_err(|e| eprintln!("server connection error: {}", e));
            handle.spawn(fut);
            Ok(())
        });
        drop(core.run(srv.select2(quitrx)));

        let record = record.borrow();
        match *record {
            Record::Capture(ref data, ref path) => {
                let data = t!(serde_json::to_string(data));
                Some((data.into_bytes(), path.clone()))
            }
            Record::Replay(..) => None,
        }
    });

    (
        ret,
        Bomb {
            iorx: Sink(sink),
            quittx: Some(quittx),
            thread: Some(thread),
        },
    )
}

struct Proxy {
    sink: Sink,
    record: Rc<RefCell<Record>>,
    client: Client,
}

impl Service for Proxy {
    type Request = hyper::Request;
    type Response = hyper::Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = hyper::Response, Error = hyper::Error>>;

    fn call(&self, req: hyper::Request) -> Self::Future {
        match *self.record.borrow_mut() {
            Record::Capture(_, _) => {
                let record = Rc::clone(&self.record);
                Box::new(
                    record_http(req, &self.client).map(move |(response, exchange)| {
                        if let Record::Capture(ref mut d, _) = *record.borrow_mut() {
                            d.push(exchange);
                        }
                        response
                    }),
                )
            }
            Record::Replay(ref mut exchanges) => {
                replay_http(req, exchanges.remove(0), &mut &self.sink)
            }
        }
    }
}

#[derive(Serialize, Deserialize)]
struct Exchange {
    request: Request,
    response: Response,
}

#[derive(Serialize, Deserialize)]
struct Request {
    uri: String,
    method: String,
    headers: HashSet<(String, String)>,
    body: Vec<u8>,
}

#[derive(Serialize, Deserialize)]
struct Response {
    status: u16,
    headers: HashSet<(String, String)>,
    body: Vec<u8>,
}

type Client = hyper::Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;

fn record_http(
    req: hyper::Request,
    client: &Client,
) -> Box<Future<Item = (hyper::Response, Exchange), Error = hyper::Error>> {
    let (method, uri, _version, headers, body) = req.deconstruct();

    let mut request = Request {
        uri: uri.to_string(),
        method: method.to_string(),
        headers: headers
            .iter()
            .map(|h| (h.name().to_string(), h.value_string()))
            .collect(),
        body: Vec::new(),
    };
    let body = body.concat2();

    let client = client.clone();
    let response = body.and_then(move |body| {
        request.body = body.to_vec();
        let uri = uri.to_string().replace("http://", "https://");
        let mut req = hyper::Request::new(method, uri.parse().unwrap());
        *req.headers_mut() = headers;
        req.set_body(body);
        client.request(req).map(|r| (r, request))
    });

    Box::new(response.and_then(|(hyper_response, request)| {
        let status = hyper_response.status();
        let headers = hyper_response.headers().clone();
        let mut response = Response {
            status: status.as_u16(),
            headers: headers
                .iter()
                .map(|h| (h.name().to_string(), h.value_string()))
                .collect(),
            body: Vec::new(),
        };

        hyper_response.body().concat2().map(move |body| {
            response.body = body.to_vec();
            let mut hyper_response = hyper::Response::new();
            hyper_response.set_body(body);
            hyper_response.set_status(status);
            *hyper_response.headers_mut() = headers;
            (
                hyper_response,
                Exchange {
                    response: response,
                    request: request,
                },
            )
        })
    }))
}

fn replay_http(
    req: hyper::Request,
    mut exchange: Exchange,
    stdout: &mut Write,
) -> Box<Future<Item = hyper::Response, Error = hyper::Error>> {
    assert_eq!(req.uri().to_string(), exchange.request.uri);
    assert_eq!(req.method().to_string(), exchange.request.method);
    t!(writeln!(
        stdout,
        "expecting: {:?}",
        exchange.request.headers
    ));
    for header in req.headers().iter() {
        let pair = (header.name().to_string(), header.value_string());
        t!(writeln!(stdout, "received: {:?}", pair));
        if header.name().starts_with("Date") {
            continue;
        }
        if header.name().starts_with("Authorization") {
            continue;
        }
        if !exchange.request.headers.remove(&pair) {
            panic!("found {:?} but didn't expect it", pair);
        }
    }
    for (name, value) in exchange.request.headers.drain() {
        if name.starts_with("Date") {
            continue;
        }
        if name.starts_with("Authorization") {
            continue;
        }
        panic!("didn't find header {:?}", (name, value));
    }
    let req_body = exchange.request.body;
    let verify_body = req.body().concat2().map(move |body| {
        assert_eq!(&body[..], &req_body[..]);
    });

    let mut response = hyper::Response::new();
    response.set_status(hyper::StatusCode::try_from(exchange.response.status).unwrap());
    for (key, value) in exchange.response.headers {
        response.headers_mut().append_raw(key, value);
    }
    response.set_body(exchange.response.body);

    Box::new(verify_body.map(|()| response))
}

impl GhUser {
    pub fn user(&'static self) -> NewUser {
        self.init.call_once(|| self.init());
        let mut u = ::new_user(self.login);
        u.gh_access_token = Cow::Owned(self.token());
        u
    }

    fn filename(&self) -> PathBuf {
        cache_file(&format!("gh-{}", self.login))
    }

    fn token(&self) -> String {
        let mut token = String::new();
        File::open(&self.filename())
            .unwrap()
            .read_to_string(&mut token)
            .unwrap();
        token
    }

    fn init(&self) {
        if fs::metadata(&self.filename()).is_ok() {
            return;
        }

        let password = ::env(&format!("GH_PASS_{}", self.login.replace("-", "_")));
        #[derive(Serialize)]
        struct Authorization {
            scopes: Vec<String>,
            note: String,
            client_id: String,
            client_secret: String,
        }
        let mut handle = Easy::new();
        let body = serde_json::to_string(&Authorization {
            scopes: vec!["read:org".to_string()],
            note: "crates.io test".to_string(),
            client_id: ::env("GH_CLIENT_ID"),
            client_secret: ::env("GH_CLIENT_SECRET"),
        }).unwrap();

        t!(handle.url("https://api.github.com/authorizations"));
        t!(handle.username(self.login));
        t!(handle.password(&password));
        t!(handle.post(true));
        t!(handle.post_fields_copy(body.as_bytes()));

        let mut headers = List::new();
        headers.append("User-Agent: hello!").unwrap();
        t!(handle.http_headers(headers));

        let mut response = Vec::new();
        {
            let mut transfer = handle.transfer();
            t!(transfer.write_function(|data| {
                response.extend(data);
                Ok(data.len())
            }));
            t!(transfer.perform())
        }

        if t!(handle.response_code()) < 200 || t!(handle.response_code()) >= 300 {
            panic!("failed to get a 200 {}", String::from_utf8_lossy(&response));
        }

        #[derive(Deserialize)]
        struct Response {
            token: String,
        }
        let resp: Response = serde_json::from_str(str::from_utf8(&response).unwrap()).unwrap();
        File::create(&self.filename())
            .unwrap()
            .write_all(resp.token.as_bytes())
            .unwrap();
    }
}
<commit_msg>Update the test http recording code to compile with hyper master<commit_after>extern crate futures;
extern crate hyper;
extern crate hyper_tls;
extern crate tokio_core;
extern crate tokio_service;

use std::borrow::Cow;
use std::collections::HashSet;
use std::env;
use std::fs::{self, File};
use std::io;
use std::io::prelude::*;
use std::net;
use std::path::PathBuf;
use std::str;
use std::sync::{Arc, Mutex, Once};
use std::thread;

use self::futures::sync::oneshot;
use self::futures::{future, Future, Stream};
use self::tokio_core::net::TcpListener;
use self::tokio_core::reactor::Core;
use curl::easy::{Easy, List};
use serde_json;

use models::NewUser;

// A "bomb" so when the test task exists we know when to shut down
// the server and fail if the subtask failed.
pub struct Bomb {
    iorx: Sink,
    quittx: Option<oneshot::Sender<()>>,
    #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
    thread: Option<thread::JoinHandle<Option<(Vec<u8>, PathBuf)>>>,
}

pub struct GhUser {
    pub login: &'static str,
    pub init: Once,
}

#[derive(Clone)]
struct Sink(Arc<Mutex<Vec<u8>>>);

impl<'a> Write for &'a Sink {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        Write::write(&mut *self.0.lock().unwrap(), data)
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for Bomb {
    fn drop(&mut self) {
        drop(self.quittx.take());
        let res = self.thread.take().unwrap().join();
        let stderr = str::from_utf8(&self.iorx.0.lock().unwrap())
            .unwrap()
            .to_string();
        match res {
            Err(..) if !thread::panicking() => panic!("server subtask failed: {}", stderr),
            Err(e) => if !stderr.is_empty() {
                println!("server subtask failed ({:?}): {}", e, stderr)
            },
            Ok(_) if thread::panicking() => {}
            Ok(None) => {}
            Ok(Some((data, file))) => {
                t!(t!(File::create(&file)).write_all(&data));
            }
        }
    }
}

fn cache_file(name: &str) -> PathBuf {
    PathBuf::from(file!())
        .parent()
        .unwrap()
        .join("http-data")
        .join(name)
}

enum Record {
    Capture(Vec<Exchange>, PathBuf),
    Replay(Vec<Exchange>),
}

pub fn proxy() -> (String, Bomb) {
    let me = thread::current().name().unwrap().to_string();
    let record = env::var("RECORD").is_ok();

    let a = t!(net::TcpListener::bind("127.0.0.1:0"));
    let ret = format!("http://{}", t!(a.local_addr()));

    let data = cache_file(&me.replace("::", "_"));
    let record = if record && !data.exists() {
        Record::Capture(Vec::new(), data)
    } else if !data.exists() {
        Record::Replay(serde_json::from_slice(b"[]").unwrap())
    } else {
        let mut body = Vec::new();
        t!(t!(File::open(&data)).read_to_end(&mut body));
        Record::Replay(serde_json::from_slice(&body).unwrap())
    };

    let sink = Arc::new(Mutex::new(Vec::new()));
    let sink2 = Sink(Arc::clone(&sink));

    let (quittx, quitrx) = oneshot::channel();

    let thread = thread::spawn(move || {
        let mut core = t!(Core::new());
        let handle = core.handle();
        let addr = t!(a.local_addr());
        let listener = t!(TcpListener::from_listener(a, &addr, &handle));
        let client = hyper::Client::builder().build(hyper_tls::HttpsConnector::new(4).unwrap());

        let record = Arc::new(Mutex::new(record));
        let srv = hyper::Server::builder(listener.incoming().map(|(l, _)| l))
            .serve(Proxy {
                sink: sink2,
                record: Arc::clone(&record),
                client,
            })
            .map_err(|e| eprintln!("server connection error: {}", e));

        drop(core.run(srv.select2(quitrx)));

        let record = record.lock().unwrap();
        match *record {
            Record::Capture(ref data, ref path) => {
                let data = t!(serde_json::to_string(data));
                Some((data.into_bytes(), path.clone()))
            }
            Record::Replay(..) => None,
        }
    });

    (
        ret,
        Bomb {
            iorx: Sink(sink),
            quittx: Some(quittx),
            thread: Some(thread),
        },
    )
}

#[derive(Clone)]
struct Proxy {
    sink: Sink,
    record: Arc<Mutex<Record>>,
    client: Client,
}

impl hyper::service::Service for Proxy {
    type ReqBody = hyper::Body;
    type ResBody = hyper::Body;
    type Error = hyper::Error;
    type Future = Box<Future<Item = hyper::Response<Self::ResBody>, Error = Self::Error> + Send>;

    fn call(&mut self, req: hyper::Request<Self::ReqBody>) -> Self::Future {
        let record2 = self.record.clone();
        match *self.record.lock().unwrap() {
            Record::Capture(_, _) => Box::new(record_http(req, &self.client).map(
                move |(response, exchange)| {
                    if let Record::Capture(ref mut d, _) = *record2.lock().unwrap() {
                        d.push(exchange);
                    }
                    response
                },
            )),
            Record::Replay(ref mut exchanges) => {
                replay_http(req, exchanges.remove(0), &mut &self.sink)
            }
        }
    }
}

impl hyper::service::NewService for Proxy {
    type ReqBody = hyper::Body;
    type ResBody = hyper::Body;
    type Error = hyper::Error;
    type Service = Proxy;
    type Future = Box<Future<Item = Self::Service, Error = Self::InitError> + Send>;
    type InitError = hyper::Error;

    fn new_service(&self) -> Self::Future {
        Box::new(future::ok(self.clone()))
    }
}

#[derive(Serialize, Deserialize)]
struct Exchange {
    request: Request,
    response: Response,
}

#[derive(Serialize, Deserialize)]
struct Request {
    uri: String,
    method: String,
    headers: HashSet<(String, String)>,
    body: Vec<u8>,
}

#[derive(Serialize, Deserialize)]
struct Response {
    status: u16,
    headers: HashSet<(String, String)>,
    body: Vec<u8>,
}

type Client = hyper::Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;

fn record_http(
    req: hyper::Request<hyper::Body>,
    client: &Client,
) -> Box<Future<Item = (hyper::Response<hyper::Body>, Exchange), Error = hyper::Error> + Send> {
    let (header_parts, body) = req.into_parts();
    let method = header_parts.method;
    let uri = header_parts.uri;
    let headers = header_parts.headers;

    let mut request = Request {
        uri: uri.to_string(),
        method: method.to_string(),
        headers: headers
            .iter()
            .map(|h| (h.0.as_str().to_string(), h.1.to_str().unwrap().to_string()))
            .collect(),
        body: Vec::new(),
    };
    let body = body.concat2();

    let client = client.clone();
    let response = body.and_then(move |body| {
        request.body = body.to_vec();
        let uri = uri.to_string().replace("http://", "https://");
        let uri = uri.parse::<hyper::Uri>().unwrap();
        let mut req = hyper::Request::builder()
            .method(method.clone())
            .uri(uri)
            .body(body.into())
            .unwrap();
        *req.headers_mut() = headers.clone();
        client.request(req).map(|r| (r, request))
    });

    Box::new(response.and_then(|(hyper_response, request)| {
        let status = hyper_response.status();
        let headers = hyper_response.headers().clone();
        let mut response = Response {
            status: status.as_u16(),
            headers: headers
                .iter()
                .map(|h| (h.0.as_str().to_string(), h.1.to_str().unwrap().to_string()))
                .collect(),
            body: Vec::new(),
        };

        hyper_response.into_body().concat2().map(move |body| {
            response.body = body.to_vec();
            let mut hyper_response = hyper::Response::builder();
            hyper_response.status(status);
            let mut hyper_response = hyper_response.body(body.into()).unwrap();
            *hyper_response.headers_mut() = headers;
            (
                hyper_response,
                Exchange {
                    response: response,
                    request: request,
                },
            )
        })
    }))
}

fn replay_http(
    req: hyper::Request<hyper::Body>,
    mut exchange: Exchange,
    stdout: &mut Write,
) -> Box<Future<Item = hyper::Response<hyper::Body>, Error = hyper::Error> + Send> {
    assert_eq!(req.uri().to_string(), exchange.request.uri);
    assert_eq!(req.method().to_string(), exchange.request.method);
    t!(writeln!(
        stdout,
        "expecting: {:?}",
        exchange.request.headers
    ));
    for (name, value) in req.headers().iter() {
        let pair = (
            name.as_str().to_string(),
            value.to_str().unwrap().to_string(),
        );
        t!(writeln!(stdout, "received: {:?}", pair));
        if name.as_str().starts_with("date") {
            continue;
        }
        if name.as_str().starts_with("authorization") {
            continue;
        }
        if !exchange.request.headers.remove(&pair) {
            panic!("found {:?} but didn't expect it", pair);
        }
    }
    for (name, value) in exchange.request.headers.drain() {
        if name.starts_with("date") {
            continue;
        }
        if name.starts_with("authorization") {
            continue;
        }
        panic!("didn't find header {:?}", (name, value));
    }
    let req_body = exchange.request.body;
    let verify_body = req.into_body().concat2().map(move |body| {
        assert_eq!(&body[..], &req_body[..]);
    });

    let mut response = hyper::Response::builder();
    response.status(hyper::StatusCode::from_u16(exchange.response.status).unwrap());
    for (key, value) in exchange.response.headers {
        response.header(key.as_str(), value.as_str());
    }
    let response = response.body(exchange.response.body.into()).unwrap();

    Box::new(verify_body.map(|()| response))
}

impl GhUser {
    pub fn user(&'static self) -> NewUser {
        self.init.call_once(|| self.init());
        let mut u = ::new_user(self.login);
        u.gh_access_token = Cow::Owned(self.token());
        u
    }

    fn filename(&self) -> PathBuf {
        cache_file(&format!("gh-{}", self.login))
    }

    fn token(&self) -> String {
        let mut token = String::new();
        File::open(&self.filename())
            .unwrap()
            .read_to_string(&mut token)
            .unwrap();
        token
    }

    fn init(&self) {
        if fs::metadata(&self.filename()).is_ok() {
            return;
        }

        let password = ::env(&format!("GH_PASS_{}", self.login.replace("-", "_")));
        #[derive(Serialize)]
        struct Authorization {
            scopes: Vec<String>,
            note: String,
            client_id: String,
            client_secret: String,
        }
        let mut handle = Easy::new();
        let body = serde_json::to_string(&Authorization {
            scopes: vec!["read:org".to_string()],
            note: "crates.io test".to_string(),
            client_id: ::env("GH_CLIENT_ID"),
            client_secret: ::env("GH_CLIENT_SECRET"),
        }).unwrap();

        t!(handle.url("https://api.github.com/authorizations"));
        t!(handle.username(self.login));
        t!(handle.password(&password));
        t!(handle.post(true));
        t!(handle.post_fields_copy(body.as_bytes()));

        let mut headers = List::new();
        headers.append("User-Agent: hello!").unwrap();
        t!(handle.http_headers(headers));

        let mut response = Vec::new();
        {
            let mut transfer = handle.transfer();
            t!(transfer.write_function(|data| {
                response.extend(data);
                Ok(data.len())
            }));
            t!(transfer.perform())
        }

        if t!(handle.response_code()) < 200 || t!(handle.response_code()) >= 300 {
            panic!("failed to get a 200 {}", String::from_utf8_lossy(&response));
        }

        #[derive(Deserialize)]
        struct Response {
            token: String,
        }
        let resp: Response = serde_json::from_str(str::from_utf8(&response).unwrap()).unwrap();
        File::create(&self.filename())
            .unwrap()
            .write_all(resp.token.as_bytes())
            .unwrap();
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix chunk connectivity<commit_after><|endoftext|>