<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use std::io;
use std::str;
use tokio_core::io::{Codec, EasyBuf};

pub struct CliCodec {
    /// Offset within the incoming EasyBuf at which newline search last ended
    search_offset: usize,
}

impl Codec for CliCodec {
    /// Input type is a tuple with the command name and an optional argument string
    type In = (String, Option<String>);

    /// Response type is just a string
    type Out = String;

    /// Find a newline, decode to a tuple of command name and argument string
    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        // Find newline
        let m = buf
            .as_slice()
            .iter()
            .skip(self.search_offset)
            .position(|&b| b == b'\n');

        match m {
            // Process the line if a newline was found
            Some(idx) => {
                println!("Found newline at position {}, started at {}", idx, self.search_offset); // XXX

                let line = buf.drain_to(self.search_offset + idx);
                buf.drain_to(1);

                self.search_offset = 0;

                match str::from_utf8(line.as_slice()) {
                    // Return the string on successful UTF-8 decode
                    // (TODO: split on the first space)
                    Ok(s) => Ok(Some(
                            ("Received".to_string(), Some(s.trim().to_string()))
                            )),

                    // Return an error if invalid UTF-8 is received
                    Err(e) => Err(io::Error::new(io::ErrorKind::Other, format!("invalid UTF-8: {:?}", e))),
                }
            },

            // Save our position if a newline wasn't found
            _ => {
                println!("Haven't received newline yet!  We started at offset {}, now at {}", self.search_offset, buf.len()); // XXX

                self.search_offset = buf.len();

                Ok(None)
            }
        }
    }

    /// Append the String to the outgoing buffer
    fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(msg.as_bytes());
        buf.push(b'\n');
        Ok(())
    }
}

fn main() {
    // TODO
    println!("Hello, world!");
}
<commit_msg>Use Default to omit CliCodec fields when initializing.<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use std::io;
use std::str;
use tokio_core::io::{Codec, EasyBuf};
use tokio_core::io::{Io, Framed};
use tokio_proto::pipeline::ServerProto;

#[derive(Default)]
pub struct CliCodec {
    /// Offset within the incoming EasyBuf at which newline search last ended
    search_offset: usize,
}

impl Codec for CliCodec {
    /// Input type is a tuple with the command name and an optional argument string
    type In = (String, Option<String>);

    /// Response type is just a string
    type Out = String;

    /// Find a newline, decode to a tuple of command name and argument string
    fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
        // Find newline
        let m = buf
            .as_slice()
            .iter()
            .skip(self.search_offset)
            .position(|&b| b == b'\n');

        match m {
            // Process the line if a newline was found
            Some(idx) => {
                println!("Found newline at position {}, started at {}", idx, self.search_offset); // XXX

                let line = buf.drain_to(self.search_offset + idx);
                buf.drain_to(1);

                self.search_offset = 0;

                match str::from_utf8(line.as_slice()) {
                    // Return the string on successful UTF-8 decode
                    // (TODO: split on the first space)
                    Ok(s) => Ok(Some(
                            ("Received".to_string(), Some(s.trim().to_string()))
                            )),

                    // Return an error if invalid UTF-8 is received
                    Err(e) => Err(io::Error::new(io::ErrorKind::Other, format!("invalid UTF-8: {:?}", e))),
                }
            },

            // Save our position if a newline wasn't found
            _ => {
                println!("Haven't received newline yet!  We started at offset {}, now at {}", self.search_offset, buf.len()); // XXX

                self.search_offset = buf.len();

                Ok(None)
            }
        }
    }

    /// Append the String to the outgoing buffer
    fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
        buf.extend(msg.as_bytes());
        buf.push(b'\n');
        Ok(())
    }
}

pub struct CliProto;

impl<T: Io + 'static> ServerProto<T> for CliProto {
    type Request = (String, Option<String>);
    type Response = String;

    type Transport = Framed<T, CliCodec>;
    type BindTransport = Result<Self::Transport, io::Error>;

    fn bind_transport(&self, io: T) -> Self::BindTransport {
        Ok(io.framed(CliCodec::default()))
    }
}

fn main() {
    // TODO
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>extern crate core;
extern crate argparse;

use std::os;
use argparse::{ArgumentParser, Collect, Store};
use core::str::FromStr;
use std::rand::{thread_rng, Rng};

enum QuoteStyle {
  None,
  All,
  WithSpaces,
}

impl FromStr for QuoteStyle {
  fn from_str(s: &str) -> Option<Self> {
    match s {
      "none" => Some(QuoteStyle::None),
      "all" => Some(QuoteStyle::All),
      "spaces" => Some(QuoteStyle::WithSpaces),
      _ => None
    }
  }
}

fn main() {
  let mut quote_style: QuoteStyle = QuoteStyle::WithSpaces;
  let mut values: Vec<String> = vec![];
  {
    let mut arg_parser = ArgumentParser::new();
    arg_parser.set_description("Shuffle input arguments and print them out");

    arg_parser.refer(&mut quote_style).add_option(&["-q", "--quote-style"],
      Box::new(Store::<QuoteStyle>),
      "Set what arguments to quote in the output. possible values: all, none, spaces");

    arg_parser.refer(&mut values).add_argument("values", Box::new(Collect::<String>), "List of values to shuffle");
    match arg_parser.parse_args() {
      Ok(()) => {},
      Err(x) => {
        os::set_exit_status(x);
        return;
      }
    }
  }

  let mut rng = thread_rng();
  rng.shuffle(values.as_mut_slice());

  print_args(&values[], quote_style);
}

fn print_args(args: &[String], quote_style: QuoteStyle) {
  for item in args.iter() {
    let quote = match quote_style {
      QuoteStyle::None => false,
      QuoteStyle::All => true,
      QuoteStyle::WithSpaces => item.find(|&: c: char| c.is_whitespace()).is_some(),
    };
    match quote {
      true => print!("\"{}\" ", item),
      false => print!("{} ", item),
    };
  }
  println!("");
}
<commit_msg>Refactored argument parsing to parse_args<commit_after>extern crate core;
extern crate argparse;

use std::os;
use argparse::{ArgumentParser, Collect, Store};
use core::str::FromStr;
use std::rand::{thread_rng, Rng};

enum QuoteStyle {
  None,
  All,
  WithSpaces,
}

struct Args {
  quote_style: QuoteStyle,
  values: Vec<String>,
}

impl FromStr for QuoteStyle {
  fn from_str(s: &str) -> Option<Self> {
    match s {
      "none" => Some(QuoteStyle::None),
      "all" => Some(QuoteStyle::All),
      "spaces" => Some(QuoteStyle::WithSpaces),
      _ => None
    }
  }
}

fn main() {
  let mut args = match parse_args() {
    Some(a) => a,
    None => return,
  };

  let mut rng = thread_rng();
  rng.shuffle(args.values.as_mut_slice());

  print_args(&args.values[], args.quote_style);
}

fn parse_args() -> Option<Args> {
  let mut quote_style: QuoteStyle = QuoteStyle::WithSpaces;
  let mut values: Vec<String> = vec![];

  {
    let mut arg_parser = ArgumentParser::new();
    arg_parser.set_description("Shuffle input arguments and print them out");

    arg_parser.refer(&mut quote_style).add_option(&["-q", "--quote-style"],
      Box::new(Store::<QuoteStyle>),
      "Set what arguments to quote in the output. possible values: all, none, spaces");

    arg_parser.refer(&mut values).add_argument("values", Box::new(Collect::<String>), "List of values to shuffle");
    match arg_parser.parse_args() {
      Ok(()) => {},
      Err(x) => {
        os::set_exit_status(x);
        return None;
      }
    }
  }

  Some(Args{ quote_style: quote_style, values: values })
}

fn print_args(args: &[String], quote_style: QuoteStyle) {
  for item in args.iter() {
    let quote = match quote_style {
      QuoteStyle::None => false,
      QuoteStyle::All => true,
      QuoteStyle::WithSpaces => item.find(|&: c: char| c.is_whitespace()).is_some(),
    };
    match quote {
      true => print!("\"{}\" ", item),
      false => print!("{} ", item),
    };
  }
  println!("");
}
<|endoftext|>


<commit_before>#![feature(tuple_indexing)]
#![feature(macro_rules)]
#![feature(phase)]
#![feature(globs)]

#[phase(plugin, link)]
extern crate log;
extern crate sdl2;
extern crate serialize;
extern crate gl;
extern crate libc;
extern crate native;
extern crate time;
extern crate getopts;

use ctrl::GameController;
use level::Level;
use libc::c_void;
use mat4::Mat4;
use player::Player;
use sdl2::scancode;
use std::default::Default;
use numvec::Vec3;
use wad::TextureDirectory;
use getopts::{optopt,optflag,getopts, usage};
use std::os;

#[macro_escape]
pub mod check_gl;
pub mod camera;
pub mod ctrl;
pub mod mat4;
pub mod numvec;
pub mod player;
pub mod shader;
pub mod wad;
pub mod level;
pub mod vbo;
pub mod line;
pub mod texture;

fn create_opengl_window(title : &str,
                        width : int,
                        height : int) -> sdl2::video::Window {
    if !sdl2::init(sdl2::InitVideo) { fail!("main: sdl video init failed."); }
    sdl2::video::gl_set_attribute(sdl2::video::GLContextMajorVersion, 3);
    sdl2::video::gl_set_attribute(sdl2::video::GLContextMinorVersion, 3);
    sdl2::video::gl_set_attribute(sdl2::video::GLDepthSize, 24);
    sdl2::video::gl_set_attribute(sdl2::video::GLDoubleBuffer, 1);
    match sdl2::video::Window::new(
            title, sdl2::video::PosCentered, sdl2::video::PosCentered,
            width, height, sdl2::video::OpenGL | sdl2::video::Shown) {
        Ok(w) => w, Err(err) => fail!("failed to create window: {}", err)
    }
}

fn init_opengl(window : &sdl2::video::Window) -> sdl2::video::GLContext {
    let context = window.gl_create_context().unwrap();
    sdl2::clear_error();
    gl::load_with(|name| {
        match sdl2::video::gl_get_proc_address(name) {
            Some(glproc) => glproc as *const libc::c_void,
            None => {
                warn!("missing GL function: {}", name);
                std::ptr::null()
            }
        }
    });
    unsafe {
        let mut vao_id = 0;
        check_gl!(gl::GenVertexArrays(1, &mut vao_id));
        check_gl!(gl::BindVertexArray(vao_id));
    }

    context
}

struct Scene {
    player: Player,
    level: Level,
}

impl Scene {
    fn new(wad_filename: &str, level_index: uint) -> Scene {
        let mut wad = wad::Archive::open(&Path::new(wad_filename)).unwrap();
        let textures = TextureDirectory::from_archive(&mut wad).unwrap();
        let level_name = *wad.get_level_name(level_index);
        let level = Level::new(&mut wad, &textures, &level_name);

        check_gl!(gl::ClearColor(0.0, 0.1, 0.4, 0.0));
        check_gl!(gl::Enable(gl::DEPTH_TEST));
        check_gl!(gl::DepthFunc(gl::LESS));
        let mut player = Player::new(Default::default());
        {
            let start = level.get_start_pos();
            player.set_position(&Vec3::new(start.x, 0.3, start.y));
        }

        Scene { player: player, level: level }
    }

    fn update(&mut self, delta_time: f32, ctrl: &GameController) {
        self.player.update(delta_time, ctrl);
        self.level.render(
            delta_time,
            &self.player.get_camera()
            .multiply_transform(&Mat4::new_identity()));
    }
}

fn main() {
    let args: Vec<String> = os::args();
    let opts = [
        optopt("i", "iwad", "set initial wad file to use (eg doom1.wad)", "FILE"),
        optopt("l", "level", "the number of the level to render (0 indexed)", "N"),
        optflag("h", "help", "print this help message and exit"),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!(f.to_string()),
    };

    if matches.opt_present("h") {
        println!("{}", usage("A rust doom renderer.", &opts));
        return;
    }

    let wad_filename = matches.opt_str("i").unwrap_or("doom1.wad".to_string());
    let level = matches.opt_str("i")
                       .and_then(|l| from_str::<uint>(l.as_slice()))
                       .unwrap_or(0);

    {
        let window = create_opengl_window("Rusty Doom v0.0.2", 1600, 900);
        let _gl_context = init_opengl(&window);

        let mut scene = Scene::new(wad_filename.as_slice(), level);
        let mut control = ctrl::GameController::new();
        let quit_gesture = ctrl::AnyGesture(
            vec![ctrl::QuitTrigger,
                 ctrl::KeyTrigger(scancode::EscapeScanCode)]);

        let mut cum_time = 0.0;
        let mut cum_updates_time = 0.0;
        let mut num_frames = 0u32;
        let mut t0 = 0.0;
        loop {
            let t1 = time::precise_time_s();
            let mut delta = t1 - t0;
            if delta < 1e-10 { delta = 1.0 / 60.0; }
            let delta = delta;
            t0 = t1;
            check_gl!(gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT));

            let updates_t0 = time::precise_time_s();

            control.update();
            if control.poll_gesture(&quit_gesture) {
                break;
            }
            scene.update(delta as f32, &control);

            let updates_t1 = time::precise_time_s();
            cum_updates_time += updates_t1 - updates_t0;

            cum_time += delta;
            num_frames += 1;
            if cum_time > 2.0 {
                let fps = num_frames as f64 / cum_time;
                let cpums = 1000.0 * cum_updates_time / num_frames as f64;
                info!("Frame time: {:.2}ms ({:.2}ms cpu, FPS: {:.2})",
                      1000.0 / fps, cpums, fps);
                cum_time = 0.0;
                cum_updates_time = 0.0;
                num_frames = 0;
            }

            window.gl_swap_window();
        }
    }
    println!("main: all tasks terminated, shutting down.");
    sdl2::quit();
}

//#[start]
//fn start(argc: int, argv: *const *const u8) -> int {
//    native::start(argc, argv, main)
//}

<commit_msg>fixed command line level flag<commit_after>#![feature(tuple_indexing)]
#![feature(macro_rules)]
#![feature(phase)]
#![feature(globs)]

#[phase(plugin, link)]
extern crate log;
extern crate sdl2;
extern crate serialize;
extern crate gl;
extern crate libc;
extern crate native;
extern crate time;
extern crate getopts;

use ctrl::GameController;
use level::Level;
use libc::c_void;
use mat4::Mat4;
use player::Player;
use sdl2::scancode;
use std::default::Default;
use numvec::Vec3;
use wad::TextureDirectory;
use getopts::{optopt,optflag,getopts, usage};
use std::os;

#[macro_escape]
pub mod check_gl;
pub mod camera;
pub mod ctrl;
pub mod mat4;
pub mod numvec;
pub mod player;
pub mod shader;
pub mod wad;
pub mod level;
pub mod vbo;
pub mod line;
pub mod texture;

fn create_opengl_window(title : &str,
                        width : int,
                        height : int) -> sdl2::video::Window {
    if !sdl2::init(sdl2::InitVideo) { fail!("main: sdl video init failed."); }
    sdl2::video::gl_set_attribute(sdl2::video::GLContextMajorVersion, 3);
    sdl2::video::gl_set_attribute(sdl2::video::GLContextMinorVersion, 3);
    sdl2::video::gl_set_attribute(sdl2::video::GLDepthSize, 24);
    sdl2::video::gl_set_attribute(sdl2::video::GLDoubleBuffer, 1);
    match sdl2::video::Window::new(
            title, sdl2::video::PosCentered, sdl2::video::PosCentered,
            width, height, sdl2::video::OpenGL | sdl2::video::Shown) {
        Ok(w) => w, Err(err) => fail!("failed to create window: {}", err)
    }
}

fn init_opengl(window : &sdl2::video::Window) -> sdl2::video::GLContext {
    let context = window.gl_create_context().unwrap();
    sdl2::clear_error();
    gl::load_with(|name| {
        match sdl2::video::gl_get_proc_address(name) {
            Some(glproc) => glproc as *const libc::c_void,
            None => {
                warn!("missing GL function: {}", name);
                std::ptr::null()
            }
        }
    });
    unsafe {
        let mut vao_id = 0;
        check_gl!(gl::GenVertexArrays(1, &mut vao_id));
        check_gl!(gl::BindVertexArray(vao_id));
    }

    context
}

struct Scene {
    player: Player,
    level: Level,
}

impl Scene {
    fn new(wad_filename: &str, level_index: uint) -> Scene {
        let mut wad = wad::Archive::open(&Path::new(wad_filename)).unwrap();
        let textures = TextureDirectory::from_archive(&mut wad).unwrap();
        let level_name = *wad.get_level_name(level_index);
        let level = Level::new(&mut wad, &textures, &level_name);

        check_gl!(gl::ClearColor(0.0, 0.1, 0.4, 0.0));
        check_gl!(gl::Enable(gl::DEPTH_TEST));
        check_gl!(gl::DepthFunc(gl::LESS));
        let mut player = Player::new(Default::default());
        {
            let start = level.get_start_pos();
            player.set_position(&Vec3::new(start.x, 0.3, start.y));
        }

        Scene { player: player, level: level }
    }

    fn update(&mut self, delta_time: f32, ctrl: &GameController) {
        self.player.update(delta_time, ctrl);
        self.level.render(
            delta_time,
            &self.player.get_camera()
            .multiply_transform(&Mat4::new_identity()));
    }
}

fn main() {
    let args: Vec<String> = os::args();
    let opts = [
        optopt("i", "iwad", "set initial wad file to use (eg doom1.wad)", "FILE"),
        optopt("l", "level", "the number of the level to render (0 indexed)", "N"),
        optflag("h", "help", "print this help message and exit"),
    ];

    let matches = match getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!(f.to_string()),
    };

    if matches.opt_present("h") {
        println!("{}", usage("A rust doom renderer.", &opts));
        return;
    }

    let wad_filename = matches.opt_str("i").unwrap_or("doom1.wad".to_string());
    let level = matches.opt_str("l")
                       .and_then(|l| from_str::<uint>(l.as_slice()))
                       .unwrap_or(0);

    {
        let window = create_opengl_window("Rusty Doom v0.0.2", 1600, 900);
        let _gl_context = init_opengl(&window);

        let mut scene = Scene::new(wad_filename.as_slice(), level);
        let mut control = ctrl::GameController::new();
        let quit_gesture = ctrl::AnyGesture(
            vec![ctrl::QuitTrigger,
                 ctrl::KeyTrigger(scancode::EscapeScanCode)]);

        let mut cum_time = 0.0;
        let mut cum_updates_time = 0.0;
        let mut num_frames = 0u32;
        let mut t0 = 0.0;
        loop {
            let t1 = time::precise_time_s();
            let mut delta = t1 - t0;
            if delta < 1e-10 { delta = 1.0 / 60.0; }
            let delta = delta;
            t0 = t1;
            check_gl!(gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT));

            let updates_t0 = time::precise_time_s();

            control.update();
            if control.poll_gesture(&quit_gesture) {
                break;
            }
            scene.update(delta as f32, &control);

            let updates_t1 = time::precise_time_s();
            cum_updates_time += updates_t1 - updates_t0;

            cum_time += delta;
            num_frames += 1;
            if cum_time > 2.0 {
                let fps = num_frames as f64 / cum_time;
                let cpums = 1000.0 * cum_updates_time / num_frames as f64;
                info!("Frame time: {:.2}ms ({:.2}ms cpu, FPS: {:.2})",
                      1000.0 / fps, cpums, fps);
                cum_time = 0.0;
                cum_updates_time = 0.0;
                num_frames = 0;
            }

            window.gl_swap_window();
        }
    }
    println!("main: all tasks terminated, shutting down.");
    sdl2::quit();
}

//#[start]
//fn start(argc: int, argv: *const *const u8) -> int {
//    native::start(argc, argv, main)
//}

<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    println!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    println!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(0, geometry);
    render_output(view.get_output());
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: &Point) {
    //println!("view_request_move: to {}, start interactive mode.", *dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: &Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, *location);
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    unsafe {
        use std::process::{Command};
        println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
                 time, &*mods_ptr, key, state);
        if state == KeyState::Pressed { return false; }
        if key == 67 {
            println!("Preparing to open the terminal...");
        let mut child = Command::new("/bin/weston-terminal").spawn()
            .unwrap_or_else(|e| { println!("Error spawning child: {}", e); panic!("1") });
        }
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: &Point) -> bool {
    println!("pointer_button: pressed {} at {}", key, *point_ptr);
    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: &Point) {
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: &LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: &LibinputDevice) {
    println!("input_destroyed");
}
<commit_msg>Fixed the window popup in the example<commit_after>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 0 as u32,
                                  h: 0 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    println!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    println!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(0, geometry);
    render_output(view.get_output());
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: &Point) {
    //println!("view_request_move: to {}, start interactive mode.", *dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: &Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, *location);
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    unsafe {
        use std::process::{Command};
        println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
                 time, &*mods_ptr, key, state);
        if state == KeyState::Pressed { return false; }
        if key == 67 {
            println!("Preparing to open the terminal...");
        let mut child = Command::new("/bin/weston-terminal").spawn()
            .unwrap_or_else(|e| { println!("Error spawning child: {}", e); panic!("1") });
        }
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: &Point) -> bool {
    println!("pointer_button: pressed {} at {}", key, *point_ptr);
    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: &Point) {
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: &LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: &LibinputDevice) {
    println!("input_destroyed");
}
<|endoftext|>


<commit_before>#![feature(slice_bytes,clone_from_slice)]

extern crate libc;
extern crate errno;
extern crate rustc_serialize; //debug hex dump

#[macro_use]
extern crate nom;

use std::io::Write;
use rustc_serialize::hex::ToHex;

const ETH_P_ALL: u16 = 0x0003;
const ETH_P_IP: u16 = 0x0800;
const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;
const RECV_BUF_LEN: usize = 1542;
const SO_ATTACH_FILTER: libc::c_int = 26;

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_filter {	/* Filter block */
	code: u16,   /* Actual filter code */
	jt: u8,	/* Jump true */
	jf: u8,	/* Jump false */
	k: u32      /* Generic multiuse field */
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct sock_fprog {     /* Required for SO_ATTACH_FILTER. */
        len: u16,    /* Number of filter blocks */
        filter: *const sock_filter
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

#[derive(Debug)]
struct EthernetFrame {
    dst: MacAddr,
    src: MacAddr,
    ty: EthernetType,
    payload: EthernetPayload,
}

#[derive(Debug)]
struct MacAddr([u8; 6]);
impl MacAddr {
    fn from_slice(s: &[u8]) -> MacAddr {
        // bit ugly, is there a better way?
        let mut m = MacAddr([0u8; 6]);
        m.0.clone_from_slice(s);
        return m;
    }
}
#[derive(Debug)]
struct IpAddr(u32);

#[derive(Debug)]
#[repr(u16)]
enum EthernetType {
    Arp = ETH_P_ARP,
    Ip = ETH_P_IP
}

#[derive(Debug)]
enum EthernetPayload {
    Arp(ArpPacket),
}

#[derive(Debug)]
struct ArpPacket {
    hwtype: u16,
    proto: u16,
    hwsize: u8,
    protosize: u8,
    opcode: u16,
    sender_mac: MacAddr,
    sender_ip: IpAddr,
    target_mac: MacAddr,
    target_ip: IpAddr
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> libc::c_int {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    if unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) } == -1 {
        let err = errno::errno();
        panic!("Error getting ifindex: {} ({})", err, err.0);
    }
    return ifr.ifr_ifindex;

}

struct SocketError {
    action: &'static str,
    err: errno::Errno
}

macro_rules! sockerr {
    ($action:expr) => {
        return Err(SocketError{ action: $action, err: errno::errno() });
    };
}

fn create_listen_socket(iface: &str) -> Result<libc::c_int, SocketError> {
    // tcpdump -dd arp and incoming
    let bpf_filter_arp_incoming: [sock_filter; 6] = [
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
        sock_filter { code: 0x15, jt: 0, jf: 3, k: 0x00000806 },
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0xfffff004 },
        sock_filter { code: 0x15, jt: 1, jf: 0, k: 0x00000004 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00040000 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00000000 },
    ];
    let bpf_filter_arp_incoming_prog: sock_fprog = sock_fprog {
        len: 6,
        filter: bpf_filter_arp_incoming.as_ptr()
    };

    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32) };
    if listen_socket == -1 {
        println!("try: sudo setcap CAP_NET_RAW+eip arpmasqd");
        sockerr!("opening socket");
    }
    let attach_filter_res = unsafe { libc::setsockopt(listen_socket, libc::SOL_SOCKET, SO_ATTACH_FILTER, std::mem::transmute(&bpf_filter_arp_incoming_prog), std::mem::size_of_val(&bpf_filter_arp_incoming_prog) as u32) };
    if attach_filter_res == -1 {
        sockerr!("attaching filter");
    }
    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ALL.to_be(),
        sll_ifindex: ifindex_from_ifname(&iface, listen_socket),
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe { libc::bind(listen_socket, std::mem::transmute(&listen_sockaddr), std::mem::size_of_val(&listen_sockaddr) as u32) };
    if bind_result == -1 {
        sockerr!("binding socket");
    }
    return Ok(listen_socket);
}

fn u16_to_be_bytes(i: u16) -> [u8;2] {
    [((i>>8) & 0xff) as u8, (i & 0xff) as u8]
}

named!(arp_packet_parser(&[u8]) -> ArpPacket, chain!(
    hwtype: call!(nom::be_u16)
    ~ proto: call!(nom::be_u16)
    ~ hwsize: call!(nom::be_u8)
    ~ protosize: call!(nom::be_u8)
    ~ opcode: call!(nom::be_u16)
    ~ sender_mac: take!(6)
    ~ sender_ip: call!(nom::be_u32)
    ~ target_mac: take!(6)
    ~ target_ip: call!(nom::be_u32),
    || {
        ArpPacket {
            hwtype: hwtype,
            proto: proto,
            hwsize: hwsize,
            protosize: protosize,
            opcode: opcode,
            sender_mac: MacAddr::from_slice(sender_mac),
            sender_ip: IpAddr(sender_ip),
            target_mac: MacAddr::from_slice(target_mac),
            target_ip: IpAddr(target_ip)
        }
    })
);

named!(eth_frame_parser(&[u8]) -> EthernetFrame, chain!(
    dst: take!(6)
    ~ src: take!(6)
    ~ _ty: tag!(u16_to_be_bytes(ETH_P_ARP))
    ~ payload: call!(arp_packet_parser),
    || {
        EthernetFrame {
            dst: MacAddr::from_slice(dst),
            src: MacAddr::from_slice(src),
            ty: EthernetType::Arp,
            payload: EthernetPayload::Arp(payload)
        }
    })
);

fn do_recv(listen_socket: libc::c_int) -> ! {
    let buf = [0u8; RECV_BUF_LEN];
    let mut recv_sockaddr = unsafe { std::mem::zeroed::<libc::sockaddr_ll>() };
    let mut recv_sockaddr_len: u32 = std::mem::size_of_val(&recv_sockaddr) as u32;
    loop {
        let recv_result = unsafe { libc::recvfrom(listen_socket, std::mem::transmute(&buf), RECV_BUF_LEN as u64, 0, std::mem::transmute(&recv_sockaddr), &mut recv_sockaddr_len) };
        if recv_result == -1 {
            let err = errno::errno();
            panic!("Error in recvfrom: {} ({})", err, err.0);
        }
        // rust has no offsetof yet so we hardcode 12 here instead
        println!("From: {}", recv_sockaddr.sll_addr[0..(recv_sockaddr_len as usize -12)].to_hex());
        //TODO minimum arp packet length?
        if recv_result >= 42 {
            if let nom::IResult::Done(_, frame) = eth_frame_parser(&buf[0..(recv_result as usize)]) {
                println!("{:?}", frame);
            } else {
                println!("parser error");
            }
        } else {
            println!("Too short frame ({}): {}", recv_result, buf[0..(recv_result as usize)].to_hex());
        }
    }
}

fn main() {
    let mut args = std::env::args();
    if args.len() != 2 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_IFACE\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    let listen_socket = create_listen_socket(&listen_iface).unwrap_or_else(|err| panic!("Error {}: {} ({})", err.action, err.err, err.err.0));

    do_recv(listen_socket);
}
<commit_msg>use match instead of unwrap_or_else<commit_after>#![feature(slice_bytes,clone_from_slice)]

extern crate libc;
extern crate errno;
extern crate rustc_serialize; //debug hex dump

#[macro_use]
extern crate nom;

use std::io::Write;
use rustc_serialize::hex::ToHex;

const ETH_P_ALL: u16 = 0x0003;
const ETH_P_IP: u16 = 0x0800;
const ETH_P_ARP: u16 = 0x0806;
const IFNAMSIZ: usize = 16; // net/if.h
const SIOCGIFINDEX: libc::c_int = 0x8933;
const RECV_BUF_LEN: usize = 1542;
const SO_ATTACH_FILTER: libc::c_int = 26;

#[repr(C)]
#[allow(non_camel_case_types)]
struct sock_filter {	/* Filter block */
	code: u16,   /* Actual filter code */
	jt: u8,	/* Jump true */
	jf: u8,	/* Jump false */
	k: u32      /* Generic multiuse field */
}

#[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Debug)]
struct sock_fprog {     /* Required for SO_ATTACH_FILTER. */
        len: u16,    /* Number of filter blocks */
        filter: *const sock_filter
}

#[repr(C)]
#[allow(non_camel_case_types)]
struct ifreq {
    ifr_name: [u8; IFNAMSIZ],
    ifr_ifindex: libc::c_int
}

#[derive(Debug)]
struct EthernetFrame {
    dst: MacAddr,
    src: MacAddr,
    ty: EthernetType,
    payload: EthernetPayload,
}

#[derive(Debug)]
struct MacAddr([u8; 6]);
impl MacAddr {
    fn from_slice(s: &[u8]) -> MacAddr {
        // bit ugly, is there a better way?
        let mut m = MacAddr([0u8; 6]);
        m.0.clone_from_slice(s);
        return m;
    }
}
#[derive(Debug)]
struct IpAddr(u32);

#[derive(Debug)]
#[repr(u16)]
enum EthernetType {
    Arp = ETH_P_ARP,
    Ip = ETH_P_IP
}

#[derive(Debug)]
enum EthernetPayload {
    Arp(ArpPacket),
}

#[derive(Debug)]
struct ArpPacket {
    hwtype: u16,
    proto: u16,
    hwsize: u8,
    protosize: u8,
    opcode: u16,
    sender_mac: MacAddr,
    sender_ip: IpAddr,
    target_mac: MacAddr,
    target_ip: IpAddr
}

fn ifindex_from_ifname(ifname: &str, sock: libc::c_int) -> libc::c_int {
    let mut ifr = ifreq {
        ifr_name: [0; IFNAMSIZ],
        ifr_ifindex: 0
    };
    std::slice::bytes::copy_memory(ifname.as_bytes(), &mut ifr.ifr_name);
    if unsafe { libc::funcs::bsd44::ioctl(sock, SIOCGIFINDEX, &ifr) } == -1 {
        let err = errno::errno();
        panic!("Error getting ifindex: {} ({})", err, err.0);
    }
    return ifr.ifr_ifindex;

}

struct SocketError {
    action: &'static str,
    err: errno::Errno
}

macro_rules! sockerr {
    ($action:expr) => {
        return Err(SocketError{ action: $action, err: errno::errno() });
    };
}

fn create_listen_socket(iface: &str) -> Result<libc::c_int, SocketError> {
    // tcpdump -dd arp and incoming
    let bpf_filter_arp_incoming: [sock_filter; 6] = [
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0x0000000c },
        sock_filter { code: 0x15, jt: 0, jf: 3, k: 0x00000806 },
        sock_filter { code: 0x28, jt: 0, jf: 0, k: 0xfffff004 },
        sock_filter { code: 0x15, jt: 1, jf: 0, k: 0x00000004 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00040000 },
        sock_filter { code: 0x06, jt: 0, jf: 0, k: 0x00000000 },
    ];
    let bpf_filter_arp_incoming_prog: sock_fprog = sock_fprog {
        len: 6,
        filter: bpf_filter_arp_incoming.as_ptr()
    };

    let listen_socket = unsafe { libc::socket(libc::AF_PACKET, libc::SOCK_RAW, ETH_P_ALL.to_be() as i32) };
    if listen_socket == -1 {
        println!("try: sudo setcap CAP_NET_RAW+eip arpmasqd");
        sockerr!("opening socket");
    }
    let attach_filter_res = unsafe { libc::setsockopt(listen_socket, libc::SOL_SOCKET, SO_ATTACH_FILTER, std::mem::transmute(&bpf_filter_arp_incoming_prog), std::mem::size_of_val(&bpf_filter_arp_incoming_prog) as u32) };
    if attach_filter_res == -1 {
        sockerr!("attaching filter");
    }
    let listen_sockaddr = libc::sockaddr_ll {
        sll_family: libc::AF_PACKET as u16,
        sll_protocol: ETH_P_ALL.to_be(),
        sll_ifindex: ifindex_from_ifname(&iface, listen_socket),
        sll_hatype: 0,
        sll_pkttype: 0,
        sll_halen: 0,
        sll_addr: [0; 8]
    };
    let bind_result = unsafe { libc::bind(listen_socket, std::mem::transmute(&listen_sockaddr), std::mem::size_of_val(&listen_sockaddr) as u32) };
    if bind_result == -1 {
        sockerr!("binding socket");
    }
    return Ok(listen_socket);
}

fn u16_to_be_bytes(i: u16) -> [u8;2] {
    [((i>>8) & 0xff) as u8, (i & 0xff) as u8]
}

named!(arp_packet_parser(&[u8]) -> ArpPacket, chain!(
    hwtype: call!(nom::be_u16)
    ~ proto: call!(nom::be_u16)
    ~ hwsize: call!(nom::be_u8)
    ~ protosize: call!(nom::be_u8)
    ~ opcode: call!(nom::be_u16)
    ~ sender_mac: take!(6)
    ~ sender_ip: call!(nom::be_u32)
    ~ target_mac: take!(6)
    ~ target_ip: call!(nom::be_u32),
    || {
        ArpPacket {
            hwtype: hwtype,
            proto: proto,
            hwsize: hwsize,
            protosize: protosize,
            opcode: opcode,
            sender_mac: MacAddr::from_slice(sender_mac),
            sender_ip: IpAddr(sender_ip),
            target_mac: MacAddr::from_slice(target_mac),
            target_ip: IpAddr(target_ip)
        }
    })
);

named!(eth_frame_parser(&[u8]) -> EthernetFrame, chain!(
    dst: take!(6)
    ~ src: take!(6)
    ~ _ty: tag!(u16_to_be_bytes(ETH_P_ARP))
    ~ payload: call!(arp_packet_parser),
    || {
        EthernetFrame {
            dst: MacAddr::from_slice(dst),
            src: MacAddr::from_slice(src),
            ty: EthernetType::Arp,
            payload: EthernetPayload::Arp(payload)
        }
    })
);

fn do_recv(listen_socket: libc::c_int) -> ! {
    let buf = [0u8; RECV_BUF_LEN];
    let mut recv_sockaddr = unsafe { std::mem::zeroed::<libc::sockaddr_ll>() };
    let mut recv_sockaddr_len: u32 = std::mem::size_of_val(&recv_sockaddr) as u32;
    loop {
        let recv_result = unsafe { libc::recvfrom(listen_socket, std::mem::transmute(&buf), RECV_BUF_LEN as u64, 0, std::mem::transmute(&recv_sockaddr), &mut recv_sockaddr_len) };
        if recv_result == -1 {
            let err = errno::errno();
            panic!("Error in recvfrom: {} ({})", err, err.0);
        }
        // rust has no offsetof yet so we hardcode 12 here instead
        println!("From: {}", recv_sockaddr.sll_addr[0..(recv_sockaddr_len as usize -12)].to_hex());
        //TODO minimum arp packet length?
        if recv_result >= 42 {
            if let nom::IResult::Done(_, frame) = eth_frame_parser(&buf[0..(recv_result as usize)]) {
                println!("{:?}", frame);
            } else {
                println!("parser error");
            }
        } else {
            println!("Too short frame ({}): {}", recv_result, buf[0..(recv_result as usize)].to_hex());
        }
    }
}

fn main() {
    let mut args = std::env::args();
    if args.len() != 2 {
        std::io::stderr().write("Usage: arpmasqd LISTEN_IFACE\n".as_ref()).unwrap();
        panic!("number of arguments");
    }
    args.next();
    //unwrap is ok because arg count has been checked
    let listen_iface = args.next().unwrap();
    match create_listen_socket(&listen_iface) {
        Ok(sock) => do_recv(sock),
        Err(err) => panic!("Error {}: {} ({})", err.action, err.err, err.err.0)
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS kernel
//! This crate contains the kernel for SOS, the Stupid Operating System.
//!
//! # SOS: the Stupid Operating System
//! SOS is a simple, tiny toy OS implemented in Rust. It targets the x86,
//! x86_64, and ARM v7 CPU architectures.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel
//! hacking, so don't expect anything new or exciting out of this project.
//!
//! SOS is copyright 2015-2016 Eliza Weisman, and is released under the terms
//! of the MIT license.

// #![crate_name = "sos_kernel"]
// #![crate_type = "staticlib"]

#![doc(html_root_url = "https://hawkw.github.io/sos-kernel/")]

#![feature( core_intrinsics )]
#![feature( lang_items, asm, naked_functions )]
#![feature( linkage )]
#![feature( const_fn
          , slice_patterns
          , associated_consts
          , unique
          , type_ascription
          , custom_derive )]
#![feature( collections )]
#![feature( question_mark )]
// #![warn( missing_docs )]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![no_std]
#![cfg_attr(not(test), no_main)]

// -- non-SOS dependencies --------------------------------------------------
extern crate collections;
extern crate rlibc;
extern crate spin;

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate bitflags;
#[macro_use] extern crate custom_derive;

// -- SOS dependencies ------------------------------------------------------
extern crate sos_alloc as alloc;

#[macro_use] extern crate sos_vga as vga;

// #[cfg(debug_assertions)]
#[macro_use]
macro_rules! debug {
    ( $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[debug][{}]{}:{}]: {}\n"
              , module_path!()
              , file!(), line!()
              , format_args!($($args)*)); }
    }
}

#[macro_use]
macro_rules! info {
    ( dots: $dots:expr, $msg:expr, status: $status:expr ) => {
        use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info][{}][{}:{}]: {} {}"
              , module_path!()
              , file!(), line!()
              , $msg, $status);
        print!("{:<38}{:>40}", concat!($dots, $msg), $status );
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info][{}][{}:{}]: {}"
              , module_path!()
              , file!(), line!()
              , format_args!($($args)*));
        print!("{}{}", $dots, format_args!($($args)*)); }
    };
    ( $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info][{}][{}:{}]: {}"
              , module_path!()
              , file!(), line!()
              , format_args!($($args)*));
        print!( $($args)* ); }
    };
}

#[macro_use]
macro_rules! infoln {
    ( dots: $dots:expr, $msg:expr, status: $status:expr ) => {
        use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info][{}][{}:{}]: {} {}\n"
              , module_path!()
              , file!(), line!()
              , $msg, $status);
        println!("{:<38}{:>40}", concat!($dots, $msg), $status );
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info][{}][{}:{}]: {}\n"
              , module_path!()
              , file!(), line!()
              , format_args!($($args)*));
        println!("{}{}", $dots, format_args!($($args)*)); }
    };
    ( $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info][{}][{}:{}]: {}\n"
              , module_path!()
              , file!(), line!()
              , format_args!($($args)*));
        println!( $($args)* ); }
    };
}

#[macro_use] pub mod macros;
#[macro_use] pub mod memory;
#[macro_use] pub mod io;

pub mod util;
pub mod params;
// pub mod multiboot2;
pub mod elf;
pub mod arch;

/// SOS version number
pub const VERSION_STRING: &'static str
    = concat!("Stupid Operating System v", env!("CARGO_PKG_VERSION"));

// pub const BUILD_STRING: &'static str
//     = concat!("Built with ", env!("RUST_VERSION"));
//
// Since the test module contains lang items, it can't be compiled when
// running tests.
#[cfg(not(test))] pub mod panic;

use arch::cpu;
use params::InitParams;
// use core::fmt::Write;

//
// #[cfg(not(debug_assertions))]
// #[macro_use]
// macro_rules! log {
//     ($descriptor:expr, $dots:expr, $msg:expr) => (
//         // arch::drivers::serial::COM1.map(|com1|
//         //     write!(com1.lock(), "{}: {}" descriptor, msg)
//         // );
//         println!("{}{}", $dots, $msg)
//     )
// }
//

/// Kernel main loop
pub fn kernel_main() -> ! {
    let mut a_vec = collections::vec::Vec::<usize>::new();
    println!( "TEST: Created a vector in kernel space! {:?}", a_vec);
    a_vec.push(1);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    a_vec.push(2);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    // loop {
    //     unsafe { asm!("int $0" :: "N" (0x80)) };
    //     println!("Test interrupt okay");
    // }
    loop { }
}

/// Kernel initialization function called from ASM
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
//  TODO: since multiboot2 is x86-specific, this needs to move to `arch`.
//  we then want the kernel entry point to be `arch_init`. we can then
//  call into `kernel_init`.
pub fn kernel_init(params: InitParams) {
    infoln!("Hello from the kernel!");

    // -- initialize interrupts ----------------------------------------------
    infoln!(dots: " . ", "Initializing interrupts:");
    unsafe {
        cpu::interrupts::initialize();
    };

    infoln!(dots: " . ", "Enabling interrupts", status: "[ OKAY ]");

    // -- initialize the heap ------------------------------------------------
    unsafe {
        infoln!( dots: " . ", "Intializing heap"
             , status: memory::init_heap(&params).unwrap_or("[ FAIL ]")
             );
        infoln!( dots: " . . "
             , "Heap begins at {:#x} and ends at {:#x}"
             , params.heap_base, params.heap_top);
    };

    println!("\n{} {}-bit\n", VERSION_STRING, arch::ARCH_BITS);
    // -- call into kernel main loop ------------------------------------------
    // (currently, this does nothing)
    kernel_main()

}

/// This fake `main` function exists only to placate `cargo test`.
#[cfg(test)]
fn main() {

}
<commit_msg>[kernel] made serial logfile more concise<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS kernel
//! This crate contains the kernel for SOS, the Stupid Operating System.
//!
//! # SOS: the Stupid Operating System
//! SOS is a simple, tiny toy OS implemented in Rust. It targets the x86,
//! x86_64, and ARM v7 CPU architectures.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel
//! hacking, so don't expect anything new or exciting out of this project.
//!
//! SOS is copyright 2015-2016 Eliza Weisman, and is released under the terms
//! of the MIT license.

// #![crate_name = "sos_kernel"]
// #![crate_type = "staticlib"]

#![doc(html_root_url = "https://hawkw.github.io/sos-kernel/")]

#![feature( core_intrinsics )]
#![feature( lang_items, asm, naked_functions )]
#![feature( linkage )]
#![feature( const_fn
          , slice_patterns
          , associated_consts
          , unique
          , type_ascription
          , custom_derive )]
#![feature( collections )]
#![feature( question_mark )]
// #![warn( missing_docs )]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![no_std]
#![cfg_attr(not(test), no_main)]

// -- non-SOS dependencies --------------------------------------------------
extern crate collections;
extern crate rlibc;
extern crate spin;

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate bitflags;
#[macro_use] extern crate custom_derive;

// -- SOS dependencies ------------------------------------------------------
extern crate sos_alloc as alloc;

#[macro_use] extern crate sos_vga as vga;

// #[cfg(debug_assertions)]
#[macro_use]
macro_rules! debug {
    ( $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[debug][{}:{}] {}: {}\n"
              , file!(), line!()
              , module_path!()
              , format_args!($($args)*)); }
    }
}

#[macro_use]
macro_rules! info {
    ( dots: $dots:expr, $msg:expr, status: $status:expr ) => {
        use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info] {}: {} {}"
              , module_path!()
              , $msg, $status);
        print!("{:<38}{:>40}", concat!($dots, $msg), $status );
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info] {}: {}"
              , module_path!()
              , format_args!($($args)*));
        print!("{}{}", $dots, format_args!($($args)*)); }
    };
    ( $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info] {}: {}"
              , module_path!()
              , format_args!($($args)*));
        print!( $($args)* ); }
    };
}

#[macro_use]
macro_rules! infoln {
    ( dots: $dots:expr, $msg:expr, status: $status:expr ) => {
        use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info] {}: {} {}\n"
              , module_path!()
              , $msg, $status);
        println!("{:<38}{:>40}", concat!($dots, $msg), $status );
    };
    ( dots: $dots:expr, $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info] {}: {}\n"
              , module_path!()
              , format_args!($($args)*));
        println!("{}{}", $dots, format_args!($($args)*)); }
    };
    ( $($args:tt)* ) => {
        { use core::fmt::Write;
        // TODO: only do this if we're in debug mode?
        write!( $crate::arch::drivers::serial::COM1.lock()
              , "[info] {}: {}\n"
              , module_path!()
              , format_args!($($args)*));
        println!( $($args)* ); }
    };
}

#[macro_use] pub mod macros;
#[macro_use] pub mod memory;
#[macro_use] pub mod io;

pub mod util;
pub mod params;
// pub mod multiboot2;
pub mod elf;
pub mod arch;

/// SOS version number
pub const VERSION_STRING: &'static str
    = concat!("Stupid Operating System v", env!("CARGO_PKG_VERSION"));

// pub const BUILD_STRING: &'static str
//     = concat!("Built with ", env!("RUST_VERSION"));
//
// Since the test module contains lang items, it can't be compiled when
// running tests.
#[cfg(not(test))] pub mod panic;

use arch::cpu;
use params::InitParams;
// use core::fmt::Write;

//
// #[cfg(not(debug_assertions))]
// #[macro_use]
// macro_rules! log {
//     ($descriptor:expr, $dots:expr, $msg:expr) => (
//         // arch::drivers::serial::COM1.map(|com1|
//         //     write!(com1.lock(), "{}: {}" descriptor, msg)
//         // );
//         println!("{}{}", $dots, $msg)
//     )
// }
//

/// Kernel main loop
pub fn kernel_main() -> ! {
    let mut a_vec = collections::vec::Vec::<usize>::new();
    println!( "TEST: Created a vector in kernel space! {:?}", a_vec);
    a_vec.push(1);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    a_vec.push(2);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    // loop {
    //     unsafe { asm!("int $0" :: "N" (0x80)) };
    //     println!("Test interrupt okay");
    // }
    loop { }
}

/// Kernel initialization function called from ASM
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
//  TODO: since multiboot2 is x86-specific, this needs to move to `arch`.
//  we then want the kernel entry point to be `arch_init`. we can then
//  call into `kernel_init`.
pub fn kernel_init(params: InitParams) {
    infoln!("Hello from the kernel!");

    // -- initialize interrupts ----------------------------------------------
    infoln!(dots: " . ", "Initializing interrupts:");
    unsafe {
        cpu::interrupts::initialize();
    };

    infoln!(dots: " . ", "Enabling interrupts", status: "[ OKAY ]");

    // -- initialize the heap ------------------------------------------------
    unsafe {
        infoln!( dots: " . ", "Intializing heap"
             , status: memory::init_heap(&params).unwrap_or("[ FAIL ]")
             );
        infoln!( dots: " . . "
             , "Heap begins at {:#x} and ends at {:#x}"
             , params.heap_base, params.heap_top);
    };

    println!("\n{} {}-bit\n", VERSION_STRING, arch::ARCH_BITS);
    // -- call into kernel main loop ------------------------------------------
    // (currently, this does nothing)
    kernel_main()

}

/// This fake `main` function exists only to placate `cargo test`.
#[cfg(test)]
fn main() {

}
<|endoftext|>


<commit_before>extern crate chrono;

extern crate rustc_serialize;
use rustc_serialize::json;

extern crate rs_es;
use rs_es::Client;
use rs_es::operations::search::{Sort, SortField, Order};
use rs_es::query::{Filter, Query};

extern crate postgres;
extern crate postgres_array;
use postgres::{Connection, SslMode};

extern crate iron;
extern crate router;
extern crate urlencoded;
use iron::prelude::*;
use iron::status;
use iron::mime::{Mime, TopLevel, SubLevel, Attr, Value};
use router::Router;
use urlencoded::UrlEncodedQuery;

mod user;
use user::User;

mod company;

mod filters;
use filters::{visibility_filters, VectorOfTerms};

use std::env;

#[derive(Debug, RustcDecodable)]
struct TalentsSearchResult {
  id: i32
}

const PG_URL:     &'static str            = "postgres://lando@localhost/lando_development";
const ES_INDEXES: &'static [&'static str] = &["honeypot_dev_talents"];
const VERSION:    &'static str            = env!("CARGO_PKG_VERSION");

fn main() {
  let port = env::args().nth(1).unwrap_or(String::from("3000"));
  let host = format!("127.0.0.1:{}", port);

  println!("Honeysearch v{}", VERSION);
  println!("Listening on http://{}...", host);

  let mut router = Router::new();
  router.get("/talents", talents);

  Iron::new(router).http(&*host).unwrap();
}

fn talents(req: &mut Request) -> IronResult<Response> {
  let mut es = Client::new("localhost", 9200);
  let     pg = Connection::connect(PG_URL, SslMode::None).unwrap();

  // TODO: How to deal with this two private parameters?
  let company_ids: Vec<i32>    = vec![];
  let company_id:  Option<i32> = None;

  let params = req.get_ref::<UrlEncodedQuery>().ok().unwrap();
  let empty_vec: Vec<String> = vec![];

  let query = Query::build_filtered(Filter::build_bool()
                                           .with_must(
                                             vec![
                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_roles", params.get("work_roles")
                                                                     .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_languages", params.get("work_languages")
                                                                        .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_experience", params.get("work_experience")
                                                                        .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_locations", params.get("work_locations")
                                                                        .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                "work_authorization", params.get("work_authorization")
                                                                        .unwrap_or(&empty_vec)),

                                               visibility_filters(&pg, &company_id)
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .with_must_not(
                                             vec![
                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "company_ids", &company_ids),

                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "blocked_companies", &company_ids)
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .build())
                    .build();

  let result = es.search_query()
                 .with_indexes(ES_INDEXES)
                 .with_query(&query)
                 .with_sort(&Sort::new(
                   vec![
                     SortField::new("updated_at", Some(Order::Desc)).build()
                   ]))
                 .send()
                 .ok()
                 .unwrap();

  let user_ids = result.hits.hits.into_iter()
                                 .filter_map(|hit| {
                                   let talent: TalentsSearchResult = hit.source().unwrap();
                                   User::find(&pg, &talent.id)
                                 })
                                 .collect::<Vec<User>>();

  let mut response = Response::with((status::Ok, json::encode(&user_ids).unwrap()));
  response.set_mut(Mime(
                    TopLevel::Application,
                    SubLevel::Json,
                    vec![
                      (Attr::Charset, Value::Utf8)
                    ]
                  ));
  Ok(response)
}
<commit_msg>main: refactor setting of the content type<commit_after>extern crate chrono;

extern crate rustc_serialize;
use rustc_serialize::json;

extern crate rs_es;
use rs_es::Client;
use rs_es::operations::search::{Sort, SortField, Order};
use rs_es::query::{Filter, Query};

extern crate postgres;
extern crate postgres_array;
use postgres::{Connection, SslMode};

extern crate iron;
extern crate router;
extern crate urlencoded;
use iron::prelude::*;
use iron::status;
use iron::mime::Mime;
use router::Router;
use urlencoded::UrlEncodedQuery;

mod user;
use user::User;

mod company;

mod filters;
use filters::{visibility_filters, VectorOfTerms};

use std::env;

#[derive(Debug, RustcDecodable)]
struct TalentsSearchResult {
  id: i32
}

const PG_URL:     &'static str            = "postgres://lando@localhost/lando_development";
const ES_INDEXES: &'static [&'static str] = &["honeypot_dev_talents"];
const VERSION:    &'static str            = env!("CARGO_PKG_VERSION");

fn main() {
  let port = env::args().nth(1).unwrap_or(String::from("3000"));
  let host = format!("127.0.0.1:{}", port);

  println!("Honeysearch v{}", VERSION);
  println!("Listening on http://{}...", host);

  let mut router = Router::new();
  router.get("/talents", talents);

  Iron::new(router).http(&*host).unwrap();
}

fn talents(req: &mut Request) -> IronResult<Response> {
  let mut es = Client::new("localhost", 9200);
  let     pg = Connection::connect(PG_URL, SslMode::None).unwrap();

  // TODO: How to deal with this two private parameters?
  let company_ids: Vec<i32>    = vec![];
  let company_id:  Option<i32> = None;

  let params = req.get_ref::<UrlEncodedQuery>().ok().unwrap();
  let empty_vec: Vec<String> = vec![];

  let query = Query::build_filtered(Filter::build_bool()
                                           .with_must(
                                             vec![
                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_roles", params.get("work_roles")
                                                                     .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_languages", params.get("work_languages")
                                                                        .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_experience", params.get("work_experience")
                                                                        .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                 "work_locations", params.get("work_locations")
                                                                        .unwrap_or(&empty_vec)),

                                               <Filter as VectorOfTerms<String>>::build_terms(
                                                "work_authorization", params.get("work_authorization")
                                                                        .unwrap_or(&empty_vec)),

                                               visibility_filters(&pg, &company_id)
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .with_must_not(
                                             vec![
                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "company_ids", &company_ids),

                                               <Filter as VectorOfTerms<i32>>::build_terms(
                                                 "blocked_companies", &company_ids)
                                             ].into_iter()
                                              .flat_map(|x| x)
                                              .collect::<Vec<Filter>>())
                                           .build())
                    .build();

  let result = es.search_query()
                 .with_indexes(ES_INDEXES)
                 .with_query(&query)
                 .with_sort(&Sort::new(
                   vec![
                     SortField::new("updated_at", Some(Order::Desc)).build()
                   ]))
                 .send()
                 .ok()
                 .unwrap();

  let user_ids = result.hits.hits.into_iter()
                                 .filter_map(|hit| {
                                   let talent: TalentsSearchResult = hit.source().unwrap();
                                   User::find(&pg, &talent.id)
                                 })
                                 .collect::<Vec<User>>();

  let content_type = "application/json".parse::<Mime>().unwrap();
  Ok(Response::with((content_type, status::Ok, json::encode(&user_ids).unwrap())))
}
<|endoftext|>