<commit_before>use field::{Field, Content};
use piston_window::*;

pub struct Game {
    field: Field,
    glyphs: Glyphs,
    mouse_x: f64,
    mouse_y: f64
}

impl Game {
    pub fn new(glyphs: Glyphs) -> Game {
        Game {
            field: Field::new(20, 20, 50),
            glyphs: glyphs,
            mouse_x: 0.0,
            mouse_y: 0.0
        }
    }

    pub fn render(&mut self, window: &PistonWindow) {
        self.draw_field(window);
    }

    fn draw_field(&mut self, window: &PistonWindow) {
        let w = window.size().width as f64;
        let h = window.size().height as f64;
        let cell_h = h / (self.field.get_height() as f64);
        let cell_w = w / (self.field.get_width() as f64);
        window.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            for i in 0..self.field.get_width() {
                for j in 0..self.field.get_height() {
                    if !self.field.revealed(i + j*self.field.get_height()) {
                        continue;
                    }
                    match *self.field.get_content(i + j*self.field.get_height()) {
                        Content::Bomb => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [(i as f64)*cell_w, (j as f64)*cell_h, cell_w, cell_h],
                                      c.transform, g);

                        },
                        Content::Number(n) => {
                            let transform = c.transform.trans((i as f64)*cell_w + 10.0, (j as f64)*cell_h + cell_h - 5.0);
                            text::Text::colored([1.0, 1.0, 1.0, 1.0], 32).draw(
                                &*n.to_string(),
                                &mut self.glyphs,
                                &c.draw_state,
                                transform, g
                            );
                        },
                        Content::None => {
                            rectangle([1.0, 1.0, 1.0, 1.0],
                                      [(i as f64)*cell_w, (j as f64)*cell_h, cell_w, cell_h],
                                      c.transform, g);
                        }
                    }
                }
            }
        });
    }

    pub fn proc_key(&mut self, button: Button, window: &PistonWindow) {
        match button {
            Button::Keyboard(key) => {
                match key {
                    Key::R => self.field.restart(),
                    _ => println!("{:?}", key)
                }
            },
            Button::Mouse(btn) => {
                match btn {
                    MouseButton::Left => {
                        let w = window.size().width as f64;
                        let h = window.size().height as f64;
                        let cell_h = h / (self.field.get_height() as f64);
                        let cell_w = w / (self.field.get_width() as f64);
                        let x = (self.mouse_x/cell_w).floor() as u32;
                        let y = (self.mouse_y/cell_h).floor() as u32;
                        let h = self.field.get_height();
                        self.open_cell(x + y*h);
                    },
                    _ => println!("{:?}", btn)
                }
            }
        }
    }

    fn open_cell(&mut self, i: u32) {
        match *self.field.reveal(i) {
            Content::Bomb => {
                self.field.reveal_all();
                println!("Game over =(, {}", i);
            },
            _ => println!("ok {}", i)
        }
    }

    pub fn mouse_move(&mut self, mouse_rel: [f64; 2]) {
        self.mouse_x = mouse_rel[0];
        self.mouse_y = mouse_rel[1];
    }
}<commit_msg>wip: minor improvements<commit_after>use field::{Field, Content};
use piston_window::*;

pub struct Game {
    field: Field,
    glyphs: Glyphs,
    mouse_x: f64,
    mouse_y: f64
}

impl Game {
    pub fn new(glyphs: Glyphs) -> Game {
        Game {
            field: Field::new(20, 20, 50),
            glyphs: glyphs,
            mouse_x: 0.0,
            mouse_y: 0.0
        }
    }

    pub fn render(&mut self, window: &PistonWindow) {
        self.draw_field(window);
    }

    fn draw_field(&mut self, window: &PistonWindow) {
        let w = window.size().width as f64;
        let h = window.size().height as f64;
        let cell_h = h / (self.field.get_height() as f64);
        let cell_w = w / (self.field.get_width() as f64);
        window.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            for i in 0..self.field.get_width() {
                for j in 0..self.field.get_height() {
                    if !self.field.revealed(i + j*self.field.get_height()) {
                        continue;
                    }
                    match *self.field.get_content(i + j*self.field.get_height()) {
                        Content::Bomb => {
                            rectangle([1.0, 0.0, 0.0, 1.0],
                                      [(i as f64)*cell_w, (j as f64)*cell_h, cell_w, cell_h],
                                      c.transform, g);

                        },
                        Content::Number(n) => {
                            let transform = c.transform.trans((i as f64)*cell_w + 10.0, (j as f64)*cell_h + cell_h - 5.0);
                            text::Text::colored([1.0, 1.0, 1.0, 1.0], 32).draw(
                                &*n.to_string(),
                                &mut self.glyphs,
                                &c.draw_state,
                                transform, g
                            );
                        },
                        Content::None => {
                            rectangle([1.0, 1.0, 1.0, 1.0],
                                      [(i as f64)*cell_w, (j as f64)*cell_h, cell_w, cell_h],
                                      c.transform, g);
                        }
                    }
                }
            }
        });
    }

    pub fn proc_key(&mut self, button: Button, window: &PistonWindow) {
        match button {
            Button::Keyboard(key) => {
                match key {
                    Key::R => self.field.restart(),
                    _ => println!("{:?}", key)
                }
            },
            Button::Mouse(btn) => {
                match btn {
                    MouseButton::Left => {
                        let w = window.size().width;
                        let h = window.size().height;
                        let cell_h = h / self.field.get_height();
                        let cell_w = w / self.field.get_width();
                        let x = (self.mouse_x.floor() as u32)/cell_w;
                        let y = (self.mouse_y.floor() as u32)/cell_h;
                        let h = self.field.get_height();
                        self.open_cell(x + y*h);
                    },
                    _ => println!("{:?}", btn)
                }
            }
        }
    }

    fn open_cell(&mut self, i: u32) {
        match *self.field.reveal(i) {
            Content::Bomb => {
                self.field.reveal_all();
                println!("Game over =(, {}", i);
            },
            _ => println!("ok {}", i)
        }
    }

    pub fn mouse_move(&mut self, mouse_rel: [f64; 2]) {
        self.mouse_x = mouse_rel[0];
        self.mouse_y = mouse_rel[1];
    }
}<|endoftext|>


<commit_before>extern crate getopts;
extern crate pnet;

use getopts::Options;
use std::os;
use std::net::{IpAddr};
use std::str::FromStr;

use pnet::transport::TransportProtocol::{Ipv4};
use pnet::old_packet::ip::IpNextHeaderProtocols;
use pnet::transport::TransportChannelType::{Layer3};
use pnet::transport::{transport_channel};
use pnet::old_packet::ipv4::{Ipv4Header, Ipv4Packet};

fn main() {
    let args: Vec<String> = os::args();
    let mut opts = Options::new();
    let matches = match opts.parse(args.tail()) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let addr_arg = matches.free[0].as_slice();
    let addr: IpAddr = FromStr::from_str(addr_arg.as_slice()).unwrap();

    let protocol = Layer3(IpNextHeaderProtocols::Test1);
    let (mut icmp_sender, mut icmp_receiver) = match transport_channel(4096, protocol) {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("An error occurred when creating the transport channel:
                        {}", e)
    };
    let packet = build_icmp_time_request_packet();
}

fn build_icmp_time_request_packet() -> IcmpRequestPacket {
    let ip_type = 14u8;
    let ip_code = 0u8;
    let ip_checksum = 0u16; // calculate; 16 bits
    let identifier = 0u16; // what should this be? used to match requests to replies; 16 bits
    let sequence = 0u16; // what should this be? used to match requests to replies;
    let originate_timestamp = 0u32; // get from systime
    let receive_timestamp = 0u32; // not used
    let transmit_timestamp = 0u32; // not used
    let mut packet = IcmpRequestPacket::new();
    packet
}

struct IcmpRequestPacket {
    ip_type: u8,
    ip_code: u8,
    ip_checksum: u16,
    identifier: u16,
    sequence: u16,
    originate_timestamp: u32,
    receive_timestamp: u32,
    transmit_timestamp: u32
}

impl IcmpRequestPacket {
    fn new() -> IcmpRequestPacket {
        let mut packet = IcmpRequestPacket {
            ip_type: 14,
            ip_code: 0,
            ip_checksum: 0,
            identifier: 0,
            sequence: 0,
            originate_timestamp: 0,
            receive_timestamp: 0,
            transmit_timestamp: 0
        };
        packet.set_checksum();
        packet
    }

    fn calculate_checksum(&self) -> u16 {
        // implement me
        1
    }

    fn set_checksum(&mut self) {
        self.ip_checksum = self.calculate_checksum();
    }
}
<commit_msg>icmp time request has type 13, 14 is for reply<commit_after>extern crate getopts;
extern crate pnet;

use getopts::Options;
use std::os;
use std::net::{IpAddr};
use std::str::FromStr;

use pnet::transport::TransportProtocol::{Ipv4};
use pnet::old_packet::ip::IpNextHeaderProtocols;
use pnet::transport::TransportChannelType::{Layer3};
use pnet::transport::{transport_channel};
use pnet::old_packet::ipv4::{Ipv4Header, Ipv4Packet};

fn main() {
    let args: Vec<String> = os::args();
    let mut opts = Options::new();
    let matches = match opts.parse(args.tail()) {
        Ok(m) => m,
        Err(f) => panic!(f.to_string())
    };
    let addr_arg = matches.free[0].as_slice();
    let addr: IpAddr = FromStr::from_str(addr_arg.as_slice()).unwrap();

    let protocol = Layer3(IpNextHeaderProtocols::Test1);
    let (mut icmp_sender, mut icmp_receiver) = match transport_channel(4096, protocol) {
        Ok((tx, rx)) => (tx, rx),
        Err(e) => panic!("An error occurred when creating the transport channel:
                        {}", e)
    };
    let packet = build_icmp_time_request_packet();
}

fn build_icmp_time_request_packet() -> IcmpRequestPacket {
    let ip_type = 14u8;
    let ip_code = 0u8;
    let ip_checksum = 0u16; // calculate; 16 bits
    let identifier = 0u16; // what should this be? used to match requests to replies; 16 bits
    let sequence = 0u16; // what should this be? used to match requests to replies;
    let originate_timestamp = 0u32; // get from systime
    let receive_timestamp = 0u32; // not used
    let transmit_timestamp = 0u32; // not used
    let mut packet = IcmpRequestPacket::new();
    packet
}

struct IcmpRequestPacket {
    ip_type: u8,
    ip_code: u8,
    ip_checksum: u16,
    identifier: u16,
    sequence: u16,
    originate_timestamp: u32,
    receive_timestamp: u32,
    transmit_timestamp: u32
}

impl IcmpRequestPacket {
    fn new() -> IcmpRequestPacket {
        let mut packet = IcmpRequestPacket {
            ip_type: 13,
            ip_code: 0,
            ip_checksum: 0,
            identifier: 0,
            sequence: 0,
            originate_timestamp: 0,
            receive_timestamp: 0,
            transmit_timestamp: 0
        };
        packet.set_checksum();
        packet
    }

    fn calculate_checksum(&self) -> u16 {
        // implement me
        1
    }

    fn set_checksum(&mut self) {
        self.ip_checksum = self.calculate_checksum();
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate rand;

mod geometry;
mod shaders;
mod interpreters;
mod lib;

use lib::LSystem;
use std::collections::HashMap;

use shaders::{VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC};

fn main() {
    use glium::{glutin, Surface};

    let mut events_loop = glutin::EventsLoop::new();
    let window = glutin::WindowBuilder::new();
    let context = glutin::ContextBuilder::new();
    let display = glium::Display::new(window, context, &events_loop).unwrap();

    let mut lsys: LSystem = LSystem::new("X".to_string());
    lsys.add('F');
    lsys.add_constant('+');
    lsys.add_constant('-');
    lsys.add_constant('[');
    lsys.add_constant(']');
    let mut rule: HashMap<char, String> = HashMap::new();
    rule.insert('X', "F[-X][X]F[-X]+FX".to_string());
    rule.insert('F', "FF".to_string());
    lsys.push(rule);

    // Iterate 6 times
    for _ in 0..1000 {
        lsys = lsys.next_rand();
    }
    println!("lsys: {}", lsys.to_string());

    let shape = interpreters::from_fractal_plant(lsys.to_string());

    let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::LinesList);

    let program =
        glium::Program::from_source(&display, VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC, None)
            .unwrap();

    let mut closed = false;
    let mut displacement_x: f32 = 0.0;
    let mut displacement_y: f32 = 0.0;
    while !closed {
        let uniforms =
            uniform! {
            view_matrix: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [displacement_x, displacement_y, 0.0, 1.0]
            ]
        };
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.05, 1.0);
        target
            .draw(
                &vertex_buffer,
                &indices,
                &program,
                &uniforms,
                &Default::default(),
            )
            .unwrap();
        target.finish().unwrap();

        events_loop.poll_events(|event| match event {
            glutin::Event::WindowEvent { event, .. } => {
                match event {
                    glutin::WindowEvent::Closed => closed = true,
                    glutin::WindowEvent::KeyboardInput {
                        device_id: _,
                        input,
                    } => {
                        println!("Key: {:?}", input.virtual_keycode.unwrap());
                        let code = input.virtual_keycode.unwrap();
                        match code {
                            glutin::VirtualKeyCode::Up => displacement_y -= 0.05,
                            glutin::VirtualKeyCode::Down => displacement_y += 0.05,
                            glutin::VirtualKeyCode::Left => displacement_x += 0.05,
                            glutin::VirtualKeyCode::Right => displacement_x -= 0.05,
                            _ => (),
                        }
                    }
                    _ => (),
                }
            }
            _ => (),
        });
    }
}
<commit_msg>Set window title name<commit_after>#[macro_use]
extern crate glium;
extern crate rand;

mod geometry;
mod shaders;
mod interpreters;
mod lib;

use lib::LSystem;
use std::collections::HashMap;

use shaders::{VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC};

fn main() {
    use glium::{glutin, Surface};

    let mut events_loop = glutin::EventsLoop::new();
    let window = glutin::WindowBuilder::new().with_title("Bismuth");
    let context = glutin::ContextBuilder::new();
    let display = glium::Display::new(window, context, &events_loop).unwrap();

    let mut lsys: LSystem = LSystem::new("X".to_string());
    lsys.add('F');
    lsys.add_constant('+');
    lsys.add_constant('-');
    lsys.add_constant('[');
    lsys.add_constant(']');
    let mut rule: HashMap<char, String> = HashMap::new();
    rule.insert('X', "F[-X][X]F[-X]+FX".to_string());
    rule.insert('F', "FF".to_string());
    lsys.push(rule);

    // Iterate 6 times
    for _ in 0..1000 {
        lsys = lsys.next_rand();
    }
    println!("lsys: {}", lsys.to_string());

    let shape = interpreters::from_fractal_plant(lsys.to_string());

    let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
    let indices = glium::index::NoIndices(glium::index::PrimitiveType::LinesList);

    let program =
        glium::Program::from_source(&display, VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC, None)
            .unwrap();

    let mut closed = false;
    let mut displacement_x: f32 = 0.0;
    let mut displacement_y: f32 = 0.0;
    while !closed {
        let uniforms =
            uniform! {
            view_matrix: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [displacement_x, displacement_y, 0.0, 1.0]
            ]
        };
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.05, 1.0);
        target
            .draw(
                &vertex_buffer,
                &indices,
                &program,
                &uniforms,
                &Default::default(),
            )
            .unwrap();
        target.finish().unwrap();

        events_loop.poll_events(|event| match event {
            glutin::Event::WindowEvent { event, .. } => {
                match event {
                    glutin::WindowEvent::Closed => closed = true,
                    glutin::WindowEvent::KeyboardInput {
                        device_id: _,
                        input,
                    } => {
                        println!("Key: {:?}", input.virtual_keycode.unwrap());
                        let code = input.virtual_keycode.unwrap();
                        match code {
                            glutin::VirtualKeyCode::Up => displacement_y -= 0.05,
                            glutin::VirtualKeyCode::Down => displacement_y += 0.05,
                            glutin::VirtualKeyCode::Left => displacement_x += 0.05,
                            glutin::VirtualKeyCode::Right => displacement_x -= 0.05,
                            _ => (),
                        }
                    }
                    _ => (),
                }
            }
            _ => (),
        });
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;

pub mod http {
    use std::net::{TcpListener, TcpStream};
    use std::io::Result;
    use std::sync::Arc;
    use std::thread;

    pub use std::net::SocketAddr;

    /// A HTTP server.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use http::{HttpServer, HttpConnection};
    ///
    /// fn handle_connection(con: HttpConnection) {
    ///   // ...
    /// }
    ///
    /// let server = HttpServer::bind("127.0.0.1:80").unwrap();
    ///
    /// // accept connections and process them
    /// server.listen(handle_connection);
    ///
    /// // close the http server
    /// drop(server);
    /// ```
    ///
    #[derive(Debug)]
    pub struct HttpServer {
        /// The underlying TCP socket listener
        tcp_listener: TcpListener,
    }

    impl HttpServer {
        /// Create a new `HttpServer` and bind it to a network address.
        ///
        /// # Arguments
        ///  - `addr` - The address to bind.
        ///
        /// # Failures
        ///  - The given address could not be bound.
        ///
        ///    Reasons for this error include
        ///    - the port already being in use, and
        ///    - the port requiring elevated permissions.
        ///
        pub fn bind(addr: &str) -> Result<HttpServer> {
            let listener = try!(TcpListener::bind(addr));

            // Log address we are listening to
            if let Ok(addr) = listener.local_addr() {
                info!("Listening on address {}", addr);
            }
            else {
                info!("Listening on unknown address");
            }

            Ok(HttpServer { tcp_listener: listener })
        }

        /// Listen for incoming connections.
        ///
        /// A new thread is spawned whenever a connection is established.
        ///
        /// # Arguments
        ///  - `cb` - A callback which is run in a new thread for each connection.
        ///
        /// # Panics
        ///  - A spawned thread could not be joined. (TODO: fix this)
        ///
        pub fn listen<F>(&self, cb: F)
            where F: Fn(HttpConnection) -> (),
                  F: 'static + Send + Sync {
            let mut handles = vec![];
            let cb = Arc::new(cb);

            // TODO: there should be a clean way to break out of this loop
            for stream in self.tcp_listener.incoming() {
                match stream {
                    Err(err) => error!("Error: {}", err),
                    Ok(stream) => {
                        let con = HttpConnection::new(stream);
                        let cb = cb.clone();
                        handles.push(thread::spawn(move || cb(con)));
                    },
                }
            }

            // Join all spawned threads
            for handle in handles {
                // TODO: proper error handling
                handle.join().unwrap();
            }
        }
    }

    /// A HTTP connection
    #[derive(Debug)]
    pub struct HttpConnection {
        /// The underlying TCP stream.
        tcp_stream: TcpStream,
    }

    impl HttpConnection {
        /// Create a new `HttpConnection`
        ///
        /// # Arguments
        ///  - `stream` - The underlying TCP stream.
        fn new(stream: TcpStream) -> HttpConnection {
            HttpConnection { tcp_stream: stream }
        }

        /// The address of the local end of the connection.
        pub fn local_addr(&self) -> Result<SocketAddr> {
            self.tcp_stream.local_addr()
        }

        /// The address of the remote end of the connection.
        pub fn remote_addr(&self) -> Result<SocketAddr> {
            self.tcp_stream.peer_addr()
        }
    }
}

extern crate env_logger;
use std::thread;

/// Handle a incoming connection.
///
/// This function is run in its own thread each time a connection is created
///
/// # Arguments
///  - `con` - The incoming connection.
///
fn handle_connection(con: http::HttpConnection) {
    info!("Connection established: {:?}", con);
    thread::sleep_ms(1000);
}

/// Create a new server and begin listening.
fn main() {
    env_logger::init().unwrap();
    match http::HttpServer::bind("localhost:80") {
        Err(err) => error!("Error: {}", err),
        Ok(server) => server.listen(handle_connection)
    }
}
<commit_msg>Let HttpServer::bind accept any `T: ToSocketAddrs`<commit_after>#[macro_use] extern crate log;

pub mod http {
    use std::net::{TcpListener, TcpStream};
    use std::io::Result;
    use std::sync::Arc;
    use std::thread;

    pub use std::net::{ToSocketAddrs, SocketAddr};

    /// A HTTP server.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use http::{HttpServer, HttpConnection};
    ///
    /// fn handle_connection(con: HttpConnection) {
    ///   // ...
    /// }
    ///
    /// let server = HttpServer::bind("127.0.0.1:80").unwrap();
    ///
    /// // accept connections and process them
    /// server.listen(handle_connection);
    ///
    /// // close the http server
    /// drop(server);
    /// ```
    ///
    #[derive(Debug)]
    pub struct HttpServer {
        /// The underlying TCP socket listener
        tcp_listener: TcpListener,
    }

    impl HttpServer {
        /// Create a new `HttpServer` and bind it to a network address.
        ///
        /// # Arguments
        ///  - `addr` - The address to bind.
        ///
        /// # Failures
        ///  - The given address could not be bound.
        ///
        ///    Reasons for this error include
        ///    - the port already being in use, and
        ///    - the port requiring elevated permissions.
        ///
        pub fn bind<A: ToSocketAddrs>(addr: A) -> Result<HttpServer> {
            let listener = try!(TcpListener::bind(addr));

            // Log address we are listening to
            if let Ok(addr) = listener.local_addr() {
                info!("Listening on address {}", addr);
            }
            else {
                info!("Listening on unknown address");
            }

            Ok(HttpServer { tcp_listener: listener })
        }

        /// Listen for incoming connections.
        ///
        /// A new thread is spawned whenever a connection is established.
        ///
        /// # Arguments
        ///  - `cb` - A callback which is run in a new thread for each connection.
        ///
        /// # Panics
        ///  - A spawned thread could not be joined. (TODO: fix this)
        ///
        pub fn listen<F>(&self, cb: F)
            where F: Fn(HttpConnection) -> (),
                  F: 'static + Send + Sync {
            let mut handles = vec![];
            let cb = Arc::new(cb);

            // TODO: there should be a clean way to break out of this loop
            for stream in self.tcp_listener.incoming() {
                match stream {
                    Err(err) => error!("Error: {}", err),
                    Ok(stream) => {
                        let con = HttpConnection::new(stream);
                        let cb = cb.clone();
                        handles.push(thread::spawn(move || cb(con)));
                    },
                }
            }

            // Join all spawned threads
            for handle in handles {
                // TODO: proper error handling
                handle.join().unwrap();
            }
        }
    }

    /// A HTTP connection
    #[derive(Debug)]
    pub struct HttpConnection {
        /// The underlying TCP stream.
        tcp_stream: TcpStream,
    }

    impl HttpConnection {
        /// Create a new `HttpConnection`
        ///
        /// # Arguments
        ///  - `stream` - The underlying TCP stream.
        fn new(stream: TcpStream) -> HttpConnection {
            HttpConnection { tcp_stream: stream }
        }

        /// The address of the local end of the connection.
        pub fn local_addr(&self) -> Result<SocketAddr> {
            self.tcp_stream.local_addr()
        }

        /// The address of the remote end of the connection.
        pub fn remote_addr(&self) -> Result<SocketAddr> {
            self.tcp_stream.peer_addr()
        }
    }
}

extern crate env_logger;
use std::thread;

/// Handle a incoming connection.
///
/// This function is run in its own thread each time a connection is created
///
/// # Arguments
///  - `con` - The incoming connection.
///
fn handle_connection(con: http::HttpConnection) {
    info!("Connection established: {:?}", con);
    thread::sleep_ms(1000);
}

/// Create a new server and begin listening.
fn main() {
    env_logger::init().unwrap();
    match http::HttpServer::bind("localhost:80") {
        Err(err) => error!("Error: {}", err),
        Ok(server) => server.listen(handle_connection)
    }
}

<|endoftext|>


<commit_before>extern crate clap;
#[macro_use]
extern crate glium;
extern crate rand;

mod grid;
mod screen;

use glium::Surface;
use glium::glutin::{ContextBuilder, WindowBuilder, EventsLoop};
use glium::glutin::{Event, WindowEvent, ElementState, KeyboardInput, MouseButton, VirtualKeyCode};

use grid::*;
use screen::*;

/// Maximum frames per second.
const FPS: u32 = 30;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 2],
}

implement_vertex!(Vertex, position);

const TITLE: &str = "Flood-It";

const VERTEX_SHADER: &str = r#"
    #version 140

    in  vec2 position;
    out vec2 v_tex_coords;

    uniform mat4 matrix;

    void main() {
        v_tex_coords = 0.5 * (position + vec2(1.0, 1.0));
        gl_Position = matrix * vec4(position, 0.0, 1.0);
    }
"#;

/// Map Color::* to RGB values.
const FRAGMENT_SHADER: &str = r#"
    #version 140

    in  vec2 v_tex_coords;
    out vec4 color;

    uniform sampler2D colors;

    void main() {
        color = texture(colors, v_tex_coords);
    }
"#;

fn generate_rectangle_vertices(left: f32, bottom: f32, right: f32, top: f32) -> Vec<Vertex> {
    vec![
        Vertex { position: [left, bottom] },
        Vertex { position: [right, bottom] },
        Vertex { position: [left, top] },
        Vertex { position: [right, bottom] },
        Vertex { position: [right, top] },
        Vertex { position: [left, top] },
    ]
}

fn main_loop<F: FnMut() -> bool>(mut callback: F) {
    use std::time::{Duration, Instant};
    use std::thread;

    let one_frame = Duration::new(0, 1_000_000_000 / FPS + 1);
    let mut last_frame = Instant::now();

    while callback() {
        let now = Instant::now();
        let remaining = one_frame.checked_sub(now - last_frame).unwrap_or_default();
        last_frame = now;
        thread::sleep(remaining);
    }
}

fn main() {
    let (colors, size) = parse_args();

    let mut events_loop = EventsLoop::new();
    let window = WindowBuilder::new().with_title(TITLE);
    let context = ContextBuilder::new();
    let display = glium::Display::new(window, context, &events_loop).unwrap();

    let program = glium::Program::from_source(&display, VERTEX_SHADER, FRAGMENT_SHADER, None)
        .unwrap();

    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let params = glium::DrawParameters {
        backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockwise,
        ..Default::default()
    };

    let mut grid = Grid::new(colors, size);
    let grid_aspect_ratio = grid.aspect_ratio();

    let mut cursor_position = (0.0, 0.0);

    let rect = {
        let tmp = generate_rectangle_vertices(-1.0, -1.0, 1.0, 1.0);
        glium::VertexBuffer::new(&display, &tmp).unwrap()
    };

    let mut screen = ScreenInfo::dummy();

    main_loop(|| {
        /*
         * Rendering
         */
        let mut target = display.draw();
        target.clear_color(0.0, 0.0, 0.0, 1.0);
        screen.init(|| (target.get_dimensions(), grid_aspect_ratio));

        let cell_texture = grid.render(&display);

        let uniforms =
            uniform! {
                colors: cell_texture.sampled()
                    //.wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
                    .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
                matrix: screen.matrix,
        };
        target
            .draw(&rect, &indices, &program, &uniforms, &params)
            .unwrap();

        target.finish().unwrap();

        /*
         * Handle events
         */
        let mut closed = false;
        events_loop.poll_events(|event| if let Event::WindowEvent { event, .. } = event {
            match event {
                WindowEvent::Closed => closed = true,
                WindowEvent::Resized(width, height) => {
                    screen.resize(width, height, grid_aspect_ratio);
                }

                WindowEvent::MouseMoved { position, .. } => cursor_position = position,

                WindowEvent::KeyboardInput {
                    input: KeyboardInput {
                        virtual_keycode: Some(key),
                        state: ElementState::Released,
                        ..
                    },
                    ..
                } => {
                    match key {
                        VirtualKeyCode::Space | VirtualKeyCode::N | VirtualKeyCode::R => {
                            if grid.solved() {
                                grid.reset();
                            }
                        }
                        VirtualKeyCode::Q => closed = true,
                        _ => (),
                    }
                }

                WindowEvent::MouseInput {
                    state: ElementState::Released,
                    button: MouseButton::Left,
                    ..
                } => {
                    if let Some((column, row)) =
                            cursor_position.0,
                            cursor_position.1,
                            grid.width(),
                            grid.height(),
                        )
                    {
                        if grid.click(row, column) {
                            if grid.won() {
                                println!(
                                    "You win! You used {} out of {} available moves.",
                                    grid.num_clicks(),
                                    grid.max_clicks()
                                );
                            } else {
                                println!(
                                    "You lose. You took {} moves but should have \
                            screen.cursor_to_grid_coords(
                                                 finished in {}.",
                                    grid.num_clicks(),
                                    grid.max_clicks()
                                );
                            }
                        }
                    }
                }
                _ => (),
            }
        });
        !closed
    });
}

/// Handle command line arguments
fn parse_args() -> (u8, u8) {
    use clap::{App, Arg};

    let matches = App::new(TITLE)
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            Arg::with_name("colors")
                .takes_value(true)
                .help("The number of different colors")
                .default_value("6"),
        )
        .arg(
            Arg::with_name("size")
                .takes_value(true)
                .help("The height and width of the grid")
                .default_value("14"),
        )
        .get_matches();

    let colors = {
        let tmp: usize = matches.value_of("colors").unwrap().parse().expect(
            "Invalid number of colors",
        );
        if tmp < 3 || tmp > COLORS.len() {
            panic!(
                "Flood-It only supports 3 through {} (inclusive) colors.",
                COLORS.len()
            );
        } else {
            tmp as u8
        }
    };

    let size: u8 = {
        let tmp: u8 = matches.value_of("size").unwrap().parse().expect(
            "Invalid grid size",
        );
        if tmp < 2 {
            panic!("Flood-It needs a grid of at least 2x2 cells.");
        } else {
            tmp
        }
    };

    (colors, size)
}
<commit_msg>Only create a new texture when something changed<commit_after>extern crate clap;
#[macro_use]
extern crate glium;
extern crate rand;

mod grid;
mod screen;

use glium::Surface;
use glium::glutin::{ContextBuilder, WindowBuilder, EventsLoop};
use glium::glutin::{Event, WindowEvent, ElementState, KeyboardInput, MouseButton, VirtualKeyCode};

use grid::*;
use screen::*;

/// Maximum frames per second.
const FPS: u32 = 30;

#[derive(Copy, Clone)]
struct Vertex {
    position: [f32; 2],
}

implement_vertex!(Vertex, position);

const TITLE: &str = "Flood-It";

const VERTEX_SHADER: &str = r#"
    #version 140

    in  vec2 position;
    out vec2 v_tex_coords;

    uniform mat4 matrix;

    void main() {
        v_tex_coords = 0.5 * (position + vec2(1.0, 1.0));
        gl_Position = matrix * vec4(position, 0.0, 1.0);
    }
"#;

/// Map Color::* to RGB values.
const FRAGMENT_SHADER: &str = r#"
    #version 140

    in  vec2 v_tex_coords;
    out vec4 color;

    uniform sampler2D colors;

    void main() {
        color = texture(colors, v_tex_coords);
    }
"#;

fn generate_rectangle_vertices(left: f32, bottom: f32, right: f32, top: f32) -> Vec<Vertex> {
    vec![
        Vertex { position: [left, bottom] },
        Vertex { position: [right, bottom] },
        Vertex { position: [left, top] },
        Vertex { position: [right, bottom] },
        Vertex { position: [right, top] },
        Vertex { position: [left, top] },
    ]
}

fn main_loop<F: FnMut() -> bool>(mut callback: F) {
    use std::time::{Duration, Instant};
    use std::thread;

    let one_frame = Duration::new(0, 1_000_000_000 / FPS + 1);
    let mut last_frame = Instant::now();

    while callback() {
        let now = Instant::now();
        let remaining = one_frame.checked_sub(now - last_frame).unwrap_or_default();
        last_frame = now;
        thread::sleep(remaining);
    }
}

fn main() {
    let (colors, size) = parse_args();

    let mut events_loop = EventsLoop::new();
    let window = WindowBuilder::new().with_title(TITLE);
    let context = ContextBuilder::new();
    let display = glium::Display::new(window, context, &events_loop).unwrap();

    let program = glium::Program::from_source(&display, VERTEX_SHADER, FRAGMENT_SHADER, None)
        .unwrap();

    let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

    let params = glium::DrawParameters {
        backface_culling: glium::draw_parameters::BackfaceCullingMode::CullCounterClockwise,
        ..Default::default()
    };

    let mut grid = Grid::new(colors, size);
    let grid_aspect_ratio = grid.aspect_ratio();

    let mut cursor_position = (0.0, 0.0);

    let rect = {
        let tmp = generate_rectangle_vertices(-1.0, -1.0, 1.0, 1.0);
        glium::VertexBuffer::new(&display, &tmp).unwrap()
    };

    let mut screen = ScreenInfo::dummy();
    let mut cell_texture = grid.render(&display);

    main_loop(|| {
        /*
         * Rendering
         */
        {
            let mut target = display.draw();
            target.clear_color(0.0, 0.0, 0.0, 1.0);
            screen.init(|| (target.get_dimensions(), grid_aspect_ratio));

            let uniforms =
                uniform! {
                    colors: cell_texture.sampled()
                        //.wrap_function(glium::uniforms::SamplerWrapFunction::Clamp)
                        .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest),
                        matrix: screen.matrix,
                };
            target
                .draw(&rect, &indices, &program, &uniforms, &params)
                .unwrap();

            target.finish().unwrap();
        }

        /*
         * Handle events
         */
        let mut closed = false;
        events_loop.poll_events(|event| {
            let mut changed = false;
            if let Event::WindowEvent { event, .. } = event {
                match event {
                    WindowEvent::Closed => closed = true,
                    WindowEvent::Resized(width, height) => {
                        screen.resize(width, height, grid_aspect_ratio);
                    }

                    WindowEvent::MouseMoved { position, .. } => cursor_position = position,

                    WindowEvent::KeyboardInput {
                        input: KeyboardInput {
                            virtual_keycode: Some(key),
                            state: ElementState::Released,
                            ..
                        },
                        ..
                    } => {
                        match key {
                            VirtualKeyCode::Space | VirtualKeyCode::N | VirtualKeyCode::R => {
                                if grid.solved() {
                                    grid.reset();
                                    changed = true;
                                }
                            }
                            VirtualKeyCode::Q => closed = true,
                            _ => (),
                        }
                    }

                    WindowEvent::MouseInput {
                        state: ElementState::Released,
                        button: MouseButton::Left,
                        ..
                    } => {
                        if let Some((column, row)) =
                            screen.cursor_to_grid_coords(
                                cursor_position.0,
                                cursor_position.1,
                                grid.width(),
                                grid.height(),
                            )
                        {
                            changed = true;
                            if grid.click(row, column) {
                                if grid.won() {
                                    println!(
                                        "You win! You used {} out of {} available moves.",
                                        grid.num_clicks(),
                                        grid.max_clicks()
                                    );
                                } else {
                                    println!(
                                        "You lose. You took {} moves but should have \
                                                 finished in {}.",
                                        grid.num_clicks(),
                                        grid.max_clicks()
                                    );
                                }
                            }
                        }
                    }
                    _ => (),
                }
            }
            if changed {
                cell_texture = grid.render(&display);
            }
        });
        !closed
    });
}

/// Handle command line arguments
fn parse_args() -> (u8, u8) {
    use clap::{App, Arg};

    let matches = App::new(TITLE)
        .author(env!("CARGO_PKG_AUTHORS"))
        .version(env!("CARGO_PKG_VERSION"))
        .arg(
            Arg::with_name("colors")
                .takes_value(true)
                .help("The number of different colors")
                .default_value("6"),
        )
        .arg(
            Arg::with_name("size")
                .takes_value(true)
                .help("The height and width of the grid")
                .default_value("14"),
        )
        .get_matches();

    let colors = {
        let tmp: usize = matches.value_of("colors").unwrap().parse().expect(
            "Invalid number of colors",
        );
        if tmp < 3 || tmp > COLORS.len() {
            panic!(
                "Flood-It only supports 3 through {} (inclusive) colors.",
                COLORS.len()
            );
        } else {
            tmp as u8
        }
    };

    let size: u8 = {
        let tmp: u8 = matches.value_of("size").unwrap().parse().expect(
            "Invalid grid size",
        );
        if tmp < 2 {
            panic!("Flood-It needs a grid of at least 2x2 cells.");
        } else {
            tmp
        }
    };

    (colors, size)
}
<|endoftext|>


<commit_before>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned
// 'PathBuf' only allows cloning, not copying
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(&idg_dir) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  // XXX clone this directory, or create a reference to it?
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   println!("Dumping items in {:?}", idg_dir);
   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<commit_msg>src/main.rs: fixed whitespace<commit_after>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned
// 'PathBuf' only allows cloning, not copying
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(&idg_dir) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  // XXX clone this directory, or create a reference to it?
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   println!("Dumping items in {:?}", idg_dir);
   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<|endoftext|>


<commit_before>extern crate clap;
extern crate git2;
extern crate yaml_rust;

use backend::Backend;
use cli::cli;
use conf::{RemoteBranch};
use conf::{Conf,get_configuration,create_default_config,Value,MonitoredRemote};
use constants::*;

use std::collections::HashMap;

use git2::Repository;

// util mod def needs to be first b/c of macro definitions and usage in other modules
#[macro_use]
mod util;
mod backend;
mod cli;
mod conf;
mod constants;

fn format_value(value: Value, data: String) -> String {
    format!("{}{}{}{}", value.pre_format, value.label, data, value.post_format)
}

fn substiute_special_values(s: String, values: &HashMap<String, String>) -> String {
    let mut r:String = s.clone();
    for (k, v) in values {
        r = r.replace(k, &v);
    }
    r
}

// struct for displaying all the data -- the actual program
struct Program {
    out: Vec<String>,
    backend: Backend,
    conf: Conf,
    debug: bool
}

impl Program {
    pub fn new(backend: Backend, conf: Conf, debug: bool) -> Program {
        let out: Vec<String> = Vec::new();
        Program { out: out, backend: backend, conf: conf, debug: debug }
    }

    // add repository state to output buffer
    fn add_repository_state(&mut self) {
        let repo_state = self.backend.get_repository_state();
        if !repo_state.is_empty() {
            self.out.push(repo_state);
        }
    }

    fn add_monitored_branches_state(&mut self) {
        let mr = match self.conf.get_remotes_monitoring() {
            Some(x) => x,
            None => return (),
        };
        for monitored_remote in mr {
            let rb: Option<RemoteBranch> = monitored_remote.remote_branch;
            let a_b = match self.backend.get_branch_ahead_behind(rb.clone()) {
                Some(x) => x,
                None => {
                    log!(self, "no ahead behind stats found for = {:?}", rb);
                    continue
                },
            };
            let local_branch_name = match a_b.local_branch_name {
                Some(l) => l,
                None => {
                    log!(self, "No local branch name.");
                    "".to_string()
                }
            };
            if monitored_remote.display_if_uptodate || a_b.ahead > 0 || a_b.behind > 0 {
                if let (Some(a_v), Some(b_v)) = (
                    self.conf.get_difference_ahead_value(),
                    self.conf.get_difference_behind_value()
                ) {
                    let mut special_values: HashMap<String, String> = HashMap::new();
                    special_values.insert("<LOCAL_BRANCH>".to_string(), local_branch_name);
                    match a_b.remote_branch_name {
                        Some(v) => special_values.insert("<REMOTE_BRANCH>".to_string(), v),
                        None => special_values.insert("<REMOTE_BRANCH>".to_string(), "".to_string()),
                    };
                    match a_b.remote_name {
                        Some(v) => special_values.insert("<REMOTE>".to_string(), v),
                        None => special_values.insert("<REMOTE>".to_string(), "".to_string()),
                    };
                    let mut local: String = format!(
                        "{}{}",
                        substiute_special_values(monitored_remote.pre_format, &special_values),
                        substiute_special_values(monitored_remote.post_format, &special_values),
                    );
                    if a_b.ahead > 0 {
                        local += &format_value(a_v, a_b.ahead.to_string());
                    }
                    if a_b.behind > 0 {
                        local += &format_value(b_v, a_b.behind.to_string());
                    }
                    self.out.push(local);
                }
            }
        }
    }

    fn add_file_status(&mut self) {
        if let Some(s) = self.backend.get_file_status() {
            if !s.is_empty() {
                let mut o = String::from("");

                if let Some(x) = s.get(NEW_KEY) {
                    match self.conf.get_new_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CHANGED_KEY) {
                    match self.conf.get_changed_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(STAGED_KEY) {
                    match self.conf.get_staged_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CONFLICTS_KEY) {
                    match self.conf.get_conflicts_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                self.out.push(o);
            }
        }
    }

    fn populate(&mut self) {
        self.add_repository_state();
        self.add_monitored_branches_state();
        self.add_file_status();
    }

    // print output buffer
    fn output(&self) {
        log!(self, "# of blocks = {}", self.out.len());
        let output = self.out.join("|");
        if self.debug {
            println!("'{}'", output);
        } else {
            println!("{}", output);
        }
    }
}

fn main() {
    let app = cli();
    let matches = app.get_matches();

    let debug_enabled = matches.is_present("debug");
    if debug_enabled { println!("Debug messages are enabled."); }

    let repo = match Repository::discover(".") {
        Ok(repo) => repo,
        // not a git repository, ignore
        Err(e) => {
            if debug_enabled { println!("This is not a git repository: {:?}", e); }
            return ();
        }
    };

    let mut conf_path: Option<String> = None;
    if matches.is_present("config") {
        conf_path = Some(String::from(matches.value_of("config").unwrap()));
    }

    let conf = get_configuration(conf_path);

    if matches.is_present(CLI_DEFAULT_CONFIG_SUBC_NAME) {
        let p = get_default_config_path();
        match create_default_config(p.clone()) {
            Ok(path) => {
                println!("Configuration file created at \"{}\"", path);
                return ();
            }
            Err(e) => {
                println!("Failed to create configuration file \"{}\": {}", p.to_str().unwrap(), e);
                return ();
            }
        };
    }

    let backend = Backend::new(repo, debug_enabled);
    let mut output = Program::new(backend, conf, debug_enabled);

    output.populate();
    output.output();
}
<commit_msg>warning: unused import<commit_after>extern crate clap;
extern crate git2;
extern crate yaml_rust;

use backend::Backend;
use cli::cli;
use conf::{RemoteBranch};
use conf::{Conf,get_configuration,create_default_config,Value};
use constants::*;

use std::collections::HashMap;

use git2::Repository;

// util mod def needs to be first b/c of macro definitions and usage in other modules
#[macro_use]
mod util;
mod backend;
mod cli;
mod conf;
mod constants;

fn format_value(value: Value, data: String) -> String {
    format!("{}{}{}{}", value.pre_format, value.label, data, value.post_format)
}

fn substiute_special_values(s: String, values: &HashMap<String, String>) -> String {
    let mut r:String = s.clone();
    for (k, v) in values {
        r = r.replace(k, &v);
    }
    r
}

// struct for displaying all the data -- the actual program
struct Program {
    out: Vec<String>,
    backend: Backend,
    conf: Conf,
    debug: bool
}

impl Program {
    pub fn new(backend: Backend, conf: Conf, debug: bool) -> Program {
        let out: Vec<String> = Vec::new();
        Program { out: out, backend: backend, conf: conf, debug: debug }
    }

    // add repository state to output buffer
    fn add_repository_state(&mut self) {
        let repo_state = self.backend.get_repository_state();
        if !repo_state.is_empty() {
            self.out.push(repo_state);
        }
    }

    fn add_monitored_branches_state(&mut self) {
        let mr = match self.conf.get_remotes_monitoring() {
            Some(x) => x,
            None => return (),
        };
        for monitored_remote in mr {
            let rb: Option<RemoteBranch> = monitored_remote.remote_branch;
            let a_b = match self.backend.get_branch_ahead_behind(rb.clone()) {
                Some(x) => x,
                None => {
                    log!(self, "no ahead behind stats found for = {:?}", rb);
                    continue
                },
            };
            let local_branch_name = match a_b.local_branch_name {
                Some(l) => l,
                None => {
                    log!(self, "No local branch name.");
                    "".to_string()
                }
            };
            if monitored_remote.display_if_uptodate || a_b.ahead > 0 || a_b.behind > 0 {
                if let (Some(a_v), Some(b_v)) = (
                    self.conf.get_difference_ahead_value(),
                    self.conf.get_difference_behind_value()
                ) {
                    let mut special_values: HashMap<String, String> = HashMap::new();
                    special_values.insert("<LOCAL_BRANCH>".to_string(), local_branch_name);
                    match a_b.remote_branch_name {
                        Some(v) => special_values.insert("<REMOTE_BRANCH>".to_string(), v),
                        None => special_values.insert("<REMOTE_BRANCH>".to_string(), "".to_string()),
                    };
                    match a_b.remote_name {
                        Some(v) => special_values.insert("<REMOTE>".to_string(), v),
                        None => special_values.insert("<REMOTE>".to_string(), "".to_string()),
                    };
                    let mut local: String = format!(
                        "{}{}",
                        substiute_special_values(monitored_remote.pre_format, &special_values),
                        substiute_special_values(monitored_remote.post_format, &special_values),
                    );
                    if a_b.ahead > 0 {
                        local += &format_value(a_v, a_b.ahead.to_string());
                    }
                    if a_b.behind > 0 {
                        local += &format_value(b_v, a_b.behind.to_string());
                    }
                    self.out.push(local);
                }
            }
        }
    }

    fn add_file_status(&mut self) {
        if let Some(s) = self.backend.get_file_status() {
            if !s.is_empty() {
                let mut o = String::from("");

                if let Some(x) = s.get(NEW_KEY) {
                    match self.conf.get_new_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CHANGED_KEY) {
                    match self.conf.get_changed_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(STAGED_KEY) {
                    match self.conf.get_staged_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                if let Some(x) = s.get(CONFLICTS_KEY) {
                    match self.conf.get_conflicts_value() {
                        Some(y) => o += &format!("{}{}{}{}", y.pre_format, y.label, x, y.post_format),
                        None => (),
                    };
                }
                self.out.push(o);
            }
        }
    }

    fn populate(&mut self) {
        self.add_repository_state();
        self.add_monitored_branches_state();
        self.add_file_status();
    }

    // print output buffer
    fn output(&self) {
        log!(self, "# of blocks = {}", self.out.len());
        let output = self.out.join("|");
        if self.debug {
            println!("'{}'", output);
        } else {
            println!("{}", output);
        }
    }
}

fn main() {
    let app = cli();
    let matches = app.get_matches();

    let debug_enabled = matches.is_present("debug");
    if debug_enabled { println!("Debug messages are enabled."); }

    let repo = match Repository::discover(".") {
        Ok(repo) => repo,
        // not a git repository, ignore
        Err(e) => {
            if debug_enabled { println!("This is not a git repository: {:?}", e); }
            return ();
        }
    };

    let mut conf_path: Option<String> = None;
    if matches.is_present("config") {
        conf_path = Some(String::from(matches.value_of("config").unwrap()));
    }

    let conf = get_configuration(conf_path);

    if matches.is_present(CLI_DEFAULT_CONFIG_SUBC_NAME) {
        let p = get_default_config_path();
        match create_default_config(p.clone()) {
            Ok(path) => {
                println!("Configuration file created at \"{}\"", path);
                return ();
            }
            Err(e) => {
                println!("Failed to create configuration file \"{}\": {}", p.to_str().unwrap(), e);
                return ();
            }
        };
    }

    let backend = Backend::new(repo, debug_enabled);
    let mut output = Program::new(backend, conf, debug_enabled);

    output.populate();
    output.output();
}
<|endoftext|>


<commit_before>extern crate base64;

extern crate byteorder;

extern crate hyper;
extern crate hyper_native_tls;

extern crate rayon;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

extern crate pem;

#[macro_use]
extern crate prettytable;

use std::{env, process};
use std::fs::File;
use std::io::{Read, Write};

use byteorder::{BigEndian, WriteBytesExt};

use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

#[derive(Deserialize)]
struct LogsResponseLogs {
    description: String,
    url: String,
    operated_by: Vec<u32>,
    disqualified_at: Option<u64>,
}

#[derive(Deserialize)]
struct LogsResponseOperators {
    name: String,
    id: u32,
}

#[derive(Deserialize)]
struct LogsResponse {
    logs: Vec<LogsResponseLogs>,
    operators: Vec<LogsResponseOperators>,
}

#[derive(Debug, Clone)]
struct Log {
    description: String,
    url: String,
    is_google: bool,
}

const LOG_LIST_URL: &'static str = "https://www.gstatic.com/ct/log_list/log_list.json";

fn fetch_trusted_ct_logs(http_client: &hyper::Client) -> Vec<Log> {
    let response = http_client.get(LOG_LIST_URL).send().unwrap();
    let logs_response: LogsResponse = serde_json::from_reader(response).unwrap();

    let mut google_id = None;
    for operator in logs_response.operators {
        if operator.name == "Google" {
            google_id = Some(operator.id);
            break;
        }
    }

    let mut logs = vec![];
    for log in logs_response.logs {
        if log.disqualified_at.is_some() {
            continue;
        }
        logs.push(Log {
            url: log.url,
            description: log.description,
            is_google: log.operated_by.contains(&google_id.unwrap()),
        });
    }

    return logs;
}

#[derive(Debug, Deserialize)]
struct SignedCertificateTimestamp {
    sct_version: u8,
    id: String,
    timestamp: u64,
    extensions: String,
    signature: String,
}

impl SignedCertificateTimestamp {
    fn to_raw_bytes(&self) -> Vec<u8> {
        let mut b = Vec::new();
        b.write_u8(self.sct_version).unwrap();

        let log_id = base64::decode(&self.id).unwrap();
        b.write(&log_id).unwrap();

        b.write_u64::<BigEndian>(self.timestamp).unwrap();

        let extensions = base64::decode(&self.extensions).unwrap();
        assert!(extensions.len() <= 65535);
        b.write_u16::<BigEndian>(extensions.len() as u16).unwrap();
        b.write(&extensions).unwrap();

        let signature = base64::decode(&self.signature).unwrap();
        b.write(&signature).unwrap();

        return b;
    }
}

fn submit_to_log(http_client: &hyper::Client,
                 url: &str,
                 payload: &[u8])
                 -> Option<SignedCertificateTimestamp> {
    let mut url = "https://".to_string() + url;
    if !url.ends_with("/") {
        url += "/";
    }
    url += "ct/v1/add-chain";
    let response = http_client.post(&url)
        .body(hyper::client::Body::BufBody(payload, payload.len()))
        .header(hyper::header::ContentType::json())
        .send();
    let response = match response {
        Ok(r) => r,
        // TODO: maybe not all of these should be silently ignored.
        Err(_) => return None,
    };

    // 400, 403, and probably some others generally indicate a log doesn't accept certs from this
    // root, or that the log isn't accepting new submissions.
    if response.status.is_client_error() {
        return None;
    }

    let parsed_response: SignedCertificateTimestamp = serde_json::from_reader(response).unwrap();

    return Some(parsed_response);
}

#[derive(Serialize)]
struct AddChainRequest {
    chain: Vec<String>,
}

fn submit_cert_to_logs<'a>(http_client: &hyper::Client,
                           logs: &'a [Log],
                           cert: Vec<Vec<u8>>)
                           -> Vec<(&'a Log, SignedCertificateTimestamp)> {
    let payload = serde_json::to_vec(&AddChainRequest {
            chain: cert.iter().map(|r| base64::encode(r)).collect(),
        })
        .unwrap();

    return logs.par_iter()
        .map(|ref log| {
            let sct = submit_to_log(http_client, &log.url, &payload);
            return (log.clone(), sct);
        })
        .filter(|&(_, ref sct)| sct.is_some())
        .map(|(log, sct)| (log, sct.unwrap()))
        .collect();
}

fn main() {
    let path = match env::args().skip(1).next() {
        Some(p) => p,
        None => {
            println!("Usage: {} <path/to/chain.pem>", env::args().next().unwrap());
            process::exit(1);
        }
    };

    let mut contents = String::new();
    File::open(path).unwrap().read_to_string(&mut contents).unwrap();

    let chain = pem::parse_many(contents)
        .into_iter()
        .filter(|p| p.tag == "CERTIFICATE")
        .map(|p| p.contents)
        .collect();

    let http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_native_tls::NativeTlsClient::new().unwrap())
    );
    let logs = fetch_trusted_ct_logs(&http_client);

    let scts = submit_cert_to_logs(&http_client, &logs, chain);

    let mut table = prettytable::Table::new();
    table.add_row(row!["Log", "SCT"]);
    for (log, sct) in scts {
        table.add_row(row![log.description, base64::encode(&sct.to_raw_bytes())]);
    }
    table.printstd();
}
<commit_msg>the latest rustfmt has opinions, and they are different<commit_after>extern crate base64;

extern crate byteorder;

extern crate hyper;
extern crate hyper_native_tls;

extern crate rayon;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

extern crate pem;

#[macro_use]
extern crate prettytable;

use std::{env, process};
use std::fs::File;
use std::io::{Read, Write};

use byteorder::{BigEndian, WriteBytesExt};

use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

#[derive(Deserialize)]
struct LogsResponseLogs {
    description: String,
    url: String,
    operated_by: Vec<u32>,
    disqualified_at: Option<u64>,
}

#[derive(Deserialize)]
struct LogsResponseOperators {
    name: String,
    id: u32,
}

#[derive(Deserialize)]
struct LogsResponse {
    logs: Vec<LogsResponseLogs>,
    operators: Vec<LogsResponseOperators>,
}

#[derive(Debug, Clone)]
struct Log {
    description: String,
    url: String,
    is_google: bool,
}

const LOG_LIST_URL: &'static str = "https://www.gstatic.com/ct/log_list/log_list.json";

fn fetch_trusted_ct_logs(http_client: &hyper::Client) -> Vec<Log> {
    let response = http_client.get(LOG_LIST_URL).send().unwrap();
    let logs_response: LogsResponse = serde_json::from_reader(response).unwrap();

    let mut google_id = None;
    for operator in logs_response.operators {
        if operator.name == "Google" {
            google_id = Some(operator.id);
            break;
        }
    }

    let mut logs = vec![];
    for log in logs_response.logs {
        if log.disqualified_at.is_some() {
            continue;
        }
        logs.push(Log {
                      url: log.url,
                      description: log.description,
                      is_google: log.operated_by.contains(&google_id.unwrap()),
                  });
    }

    return logs;
}

#[derive(Debug, Deserialize)]
struct SignedCertificateTimestamp {
    sct_version: u8,
    id: String,
    timestamp: u64,
    extensions: String,
    signature: String,
}

impl SignedCertificateTimestamp {
    fn to_raw_bytes(&self) -> Vec<u8> {
        let mut b = Vec::new();
        b.write_u8(self.sct_version).unwrap();

        let log_id = base64::decode(&self.id).unwrap();
        b.write(&log_id).unwrap();

        b.write_u64::<BigEndian>(self.timestamp).unwrap();

        let extensions = base64::decode(&self.extensions).unwrap();
        assert!(extensions.len() <= 65535);
        b.write_u16::<BigEndian>(extensions.len() as u16)
            .unwrap();
        b.write(&extensions).unwrap();

        let signature = base64::decode(&self.signature).unwrap();
        b.write(&signature).unwrap();

        return b;
    }
}

fn submit_to_log(http_client: &hyper::Client,
                 url: &str,
                 payload: &[u8])
                 -> Option<SignedCertificateTimestamp> {
    let mut url = "https://".to_string() + url;
    if !url.ends_with("/") {
        url += "/";
    }
    url += "ct/v1/add-chain";
    let response = http_client
        .post(&url)
        .body(hyper::client::Body::BufBody(payload, payload.len()))
        .header(hyper::header::ContentType::json())
        .send();
    let response = match response {
        Ok(r) => r,
        // TODO: maybe not all of these should be silently ignored.
        Err(_) => return None,
    };

    // 400, 403, and probably some others generally indicate a log doesn't accept certs from this
    // root, or that the log isn't accepting new submissions.
    if response.status.is_client_error() {
        return None;
    }

    let parsed_response: SignedCertificateTimestamp = serde_json::from_reader(response).unwrap();

    return Some(parsed_response);
}

#[derive(Serialize)]
struct AddChainRequest {
    chain: Vec<String>,
}

fn submit_cert_to_logs<'a>(http_client: &hyper::Client,
                           logs: &'a [Log],
                           cert: Vec<Vec<u8>>)
                           -> Vec<(&'a Log, SignedCertificateTimestamp)> {
    let payload = serde_json::to_vec(&AddChainRequest {
                                          chain: cert.iter().map(|r| base64::encode(r)).collect(),
                                      })
            .unwrap();

    return logs.par_iter()
               .map(|ref log| {
                        let sct = submit_to_log(http_client, &log.url, &payload);
                        return (log.clone(), sct);
                    })
               .filter(|&(_, ref sct)| sct.is_some())
               .map(|(log, sct)| (log, sct.unwrap()))
               .collect();
}

fn main() {
    let path = match env::args().skip(1).next() {
        Some(p) => p,
        None => {
            println!("Usage: {} <path/to/chain.pem>", env::args().next().unwrap());
            process::exit(1);
        }
    };

    let mut contents = String::new();
    File::open(path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    let chain = pem::parse_many(contents)
        .into_iter()
        .filter(|p| p.tag == "CERTIFICATE")
        .map(|p| p.contents)
        .collect();

    let http_client = hyper::Client::with_connector(
        hyper::net::HttpsConnector::new(hyper_native_tls::NativeTlsClient::new().unwrap())
    );
    let logs = fetch_trusted_ct_logs(&http_client);

    let scts = submit_cert_to_logs(&http_client, &logs, chain);

    let mut table = prettytable::Table::new();
    table.add_row(row!["Log", "SCT"]);
    for (log, sct) in scts {
        table.add_row(row![log.description, base64::encode(&sct.to_raw_bytes())]);
    }
    table.printstd();
}
<|endoftext|>


<commit_before>extern crate mqtt;
extern crate serde_json;
extern crate rs_jsonpath;
#[macro_use]
extern crate clap;
extern crate itertools;

use std::net::{TcpListener, TcpStream};
use std::thread;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::sync::Arc;

use mqtt::{Encodable, Decodable};
use mqtt::packet::{ConnackPacket, Packet, PingrespPacket, PubackPacket, PublishPacket, PubrecPacket, PubcompPacket, SubackPacket, VariablePacket};
use mqtt::{TopicFilter, QualityOfService};
use mqtt::control::ConnectReturnCode;
use mqtt::packet::suback::SubscribeReturnCode;
use mqtt::packet::publish::QoSWithPacketIdentifier;

mod csv_data_processor;
use csv_data_processor::CsvDataProcessor;

macro_rules! log(
    ($($arg:tt)*) => { {
        let _ = writeln!(&mut ::std::io::stderr(), $($arg)*);
    } }
);

#[derive(Debug)]
enum ZinkError<'a> {
    Mqtt(mqtt::packet::VariablePacketError<'a>),
    NotMqttConnect,
}

impl<'a, P> From<mqtt::packet::PacketError<'a, P>> for ZinkError<'a>
    where P: mqtt::packet::Packet<'a>,
          mqtt::packet::VariablePacketError<'a>: std::convert::From<mqtt::packet::PacketError<'a, P>> {

    fn from(err: mqtt::packet::PacketError<'a, P>) -> ZinkError<'a> {
        ZinkError::Mqtt(mqtt::packet::VariablePacketError::from(err))
    }
}

impl<'a> From<mqtt::packet::VariablePacketError<'a>> for ZinkError<'a> {
    fn from(err: mqtt::packet::VariablePacketError<'a>) -> ZinkError<'a> {
        ZinkError::Mqtt(err)
    }
}

fn main() {
    let matches = clap_app!(
        zink =>
            (version: "0.1.0")
            (@arg file: -f --file +takes_value "File to append result to. If not specified, send results to stdout")
            (@arg bind: -b --bind +takes_value default_value("0.0.0.0:1883") "Bind address and port")
            (@arg JSONPATH: +required "JSON paths to use")
    ).get_matches();

    let jsonpaths: Vec<String> = matches.value_of("JSONPATH").unwrap().split(",").map(String::from).collect();

    let handle: Box<Write + Send> = if let Some(filepath) = matches.value_of("file") {
        Box::new(OpenOptions::new()
                 .append(true)
                 .create(true)
                 .open(filepath)
                 .unwrap()) as Box<Write + Send>
    } else {
        Box::new(io::stdout()) as Box<Write + Send>
    };

    let csv_data_processor = Arc::new(CsvDataProcessor::new(handle, jsonpaths));

    let bind_address = matches.value_of("bind").unwrap();
    let listener = TcpListener::bind(bind_address).unwrap();

    log!("Bound to {}", bind_address);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let csv_data_processor = csv_data_processor.clone();
                thread::spawn(move || {
                    let res = handle_client(stream, &|ref x: &PublishPacket| {
                        csv_data_processor.process_publish(x);
                    });
                    log!("handle_client exited with {:?}", res);
                });
            }
            Err(e) => {
                log!("{}", e);
            }
        }
    }
}

fn sub_to_ack(&(_, qos): &(TopicFilter, QualityOfService)) -> SubscribeReturnCode {
    match qos {
        QualityOfService::Level0 => SubscribeReturnCode::MaximumQoSLevel0,
        QualityOfService::Level1 => SubscribeReturnCode::MaximumQoSLevel1,
        QualityOfService::Level2 => SubscribeReturnCode::MaximumQoSLevel1,
    }
}

fn handle_client<'a, 'b>(mut stream: TcpStream, process_publish: &'b Fn(&PublishPacket)) -> Result<(), ZinkError<'a>> {
    // This makes .read() call blocking.
    // Otherwise, mqtt decode consumes 100% CPU time.
    let _ = stream.set_read_timeout(None);

    log!("{:?}", stream);
    if let Ok(VariablePacket::ConnectPacket(x)) = VariablePacket::decode(&mut stream) {
        log!("{:?}", x);
        try!(ConnackPacket::new(false, ConnectReturnCode::ConnectionAccepted).encode(&mut stream));
    } else {
        return Err(ZinkError::NotMqttConnect);
    }

    loop {
        let packet = try!(VariablePacket::decode(&mut stream));
        log!("{:?}", packet);
        match packet {
            VariablePacket::SubscribePacket(x) => {
                try!(SubackPacket::new(
                    x.packet_identifier(),
                    x.payload().subscribes().into_iter().map(sub_to_ack).collect()
                ).encode(&mut stream));
            }
            VariablePacket::PingreqPacket(_) => {
                try!(PingrespPacket::new()
                     .encode(&mut stream));
            }
            VariablePacket::PubrelPacket(x) => {
                try!(PubcompPacket::new(x.packet_identifier())
                     .encode(&mut stream));
            }
            VariablePacket::PublishPacket(x) => {
                match x.qos() {
                    QoSWithPacketIdentifier::Level0 => {
                        // No additional handling is required
                    }
                    QoSWithPacketIdentifier::Level1(pkid) => {
                        try!(PubackPacket::new(pkid)
                             .encode(&mut stream));
                    }
                    QoSWithPacketIdentifier::Level2(pkid) => {
                        try!(PubrecPacket::new(pkid)
                             .encode(&mut stream));
                    }
                }

                if let Ok(payload) = std::str::from_utf8(x.payload()) {
                    log!("{}: {}", x.topic_name(), payload);
                } else {
                    log!("{}: {:?}", x.topic_name(), x.payload());
                }

                process_publish(&x);
            }
            _ => {
            }
        }
    }
}
<commit_msg>Handle Disconnect packet<commit_after>extern crate mqtt;
extern crate serde_json;
extern crate rs_jsonpath;
#[macro_use]
extern crate clap;
extern crate itertools;

use std::net::{TcpListener, TcpStream};
use std::thread;
use std::fs::OpenOptions;
use std::io::{self, Write};
use std::sync::Arc;

use mqtt::{Encodable, Decodable};
use mqtt::packet::{ConnackPacket, Packet, PingrespPacket, PubackPacket, PublishPacket, PubrecPacket, PubcompPacket, SubackPacket, VariablePacket};
use mqtt::{TopicFilter, QualityOfService};
use mqtt::control::ConnectReturnCode;
use mqtt::packet::suback::SubscribeReturnCode;
use mqtt::packet::publish::QoSWithPacketIdentifier;

mod csv_data_processor;
use csv_data_processor::CsvDataProcessor;

macro_rules! log(
    ($($arg:tt)*) => { {
        let _ = writeln!(&mut ::std::io::stderr(), $($arg)*);
    } }
);

#[derive(Debug)]
enum ZinkError<'a> {
    Mqtt(mqtt::packet::VariablePacketError<'a>),
    NotMqttConnect,
}

impl<'a, P> From<mqtt::packet::PacketError<'a, P>> for ZinkError<'a>
    where P: mqtt::packet::Packet<'a>,
          mqtt::packet::VariablePacketError<'a>: std::convert::From<mqtt::packet::PacketError<'a, P>> {

    fn from(err: mqtt::packet::PacketError<'a, P>) -> ZinkError<'a> {
        ZinkError::Mqtt(mqtt::packet::VariablePacketError::from(err))
    }
}

impl<'a> From<mqtt::packet::VariablePacketError<'a>> for ZinkError<'a> {
    fn from(err: mqtt::packet::VariablePacketError<'a>) -> ZinkError<'a> {
        ZinkError::Mqtt(err)
    }
}

fn main() {
    let matches = clap_app!(
        zink =>
            (version: "0.1.0")
            (@arg file: -f --file +takes_value "File to append result to. If not specified, send results to stdout")
            (@arg bind: -b --bind +takes_value default_value("0.0.0.0:1883") "Bind address and port")
            (@arg JSONPATH: +required "JSON paths to use")
    ).get_matches();

    let jsonpaths: Vec<String> = matches.value_of("JSONPATH").unwrap().split(",").map(String::from).collect();

    let handle: Box<Write + Send> = if let Some(filepath) = matches.value_of("file") {
        Box::new(OpenOptions::new()
                 .append(true)
                 .create(true)
                 .open(filepath)
                 .unwrap()) as Box<Write + Send>
    } else {
        Box::new(io::stdout()) as Box<Write + Send>
    };

    let csv_data_processor = Arc::new(CsvDataProcessor::new(handle, jsonpaths));

    let bind_address = matches.value_of("bind").unwrap();
    let listener = TcpListener::bind(bind_address).unwrap();

    log!("Bound to {}", bind_address);

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                let csv_data_processor = csv_data_processor.clone();
                thread::spawn(move || {
                    let res = handle_client(stream, &|ref x: &PublishPacket| {
                        csv_data_processor.process_publish(x);
                    });
                    log!("handle_client exited with {:?}", res);
                });
            }
            Err(e) => {
                log!("{}", e);
            }
        }
    }
}

fn sub_to_ack(&(_, qos): &(TopicFilter, QualityOfService)) -> SubscribeReturnCode {
    match qos {
        QualityOfService::Level0 => SubscribeReturnCode::MaximumQoSLevel0,
        QualityOfService::Level1 => SubscribeReturnCode::MaximumQoSLevel1,
        QualityOfService::Level2 => SubscribeReturnCode::MaximumQoSLevel1,
    }
}

fn handle_client<'a, 'b>(mut stream: TcpStream, process_publish: &'b Fn(&PublishPacket)) -> Result<(), ZinkError<'a>> {
    // This makes .read() call blocking.
    // Otherwise, mqtt decode consumes 100% CPU time.
    let _ = stream.set_read_timeout(None);

    log!("{:?}", stream);
    if let Ok(VariablePacket::ConnectPacket(x)) = VariablePacket::decode(&mut stream) {
        log!("{:?}", x);
        try!(ConnackPacket::new(false, ConnectReturnCode::ConnectionAccepted).encode(&mut stream));
    } else {
        return Err(ZinkError::NotMqttConnect);
    }

    loop {
        let packet = try!(VariablePacket::decode(&mut stream));
        log!("{:?}", packet);
        match packet {
            VariablePacket::DisconnectPacket(_) => {
                return Ok(());
            }
            VariablePacket::SubscribePacket(x) => {
                try!(SubackPacket::new(
                    x.packet_identifier(),
                    x.payload().subscribes().into_iter().map(sub_to_ack).collect()
                ).encode(&mut stream));
            }
            VariablePacket::PingreqPacket(_) => {
                try!(PingrespPacket::new()
                     .encode(&mut stream));
            }
            VariablePacket::PubrelPacket(x) => {
                try!(PubcompPacket::new(x.packet_identifier())
                     .encode(&mut stream));
            }
            VariablePacket::PublishPacket(x) => {
                match x.qos() {
                    QoSWithPacketIdentifier::Level0 => {
                        // No additional handling is required
                    }
                    QoSWithPacketIdentifier::Level1(pkid) => {
                        try!(PubackPacket::new(pkid)
                             .encode(&mut stream));
                    }
                    QoSWithPacketIdentifier::Level2(pkid) => {
                        try!(PubrecPacket::new(pkid)
                             .encode(&mut stream));
                    }
                }

                if let Ok(payload) = std::str::from_utf8(x.payload()) {
                    log!("{}: {}", x.topic_name(), payload);
                } else {
                    log!("{}: {:?}", x.topic_name(), x.payload());
                }

                process_publish(&x);
            }
            _ => {
            }
        }
    }
}
<|endoftext|>