<commit_before>use std::fmt::Debug;
use std::hash::Hash;
use std::collections::HashSet;

pub trait SearchSpace {
    type State: Ord + Hash + Eq + Clone + Debug;
    type Action: Clone;
    type Iterator: Iterator<Item=Self::Action>;

    fn actions(&self, state: &Self::State) -> Self::Iterator;
    fn next_state(&self, state: &Self::State, action: &Self::Action) -> Self::State;
    fn is_goal(&self, state: &Self::State) -> bool;
}

pub fn depth_first_search<S>(space: &S, start: S::State) -> Option<Vec<S::Action>>
where S: SearchSpace {
    let mut path = Vec::new();
    let actions = space.actions(&start);
    let mut frontier = vec![(start, actions)];

    loop {
        let result = match frontier.last_mut() {
            None => return None,
            Some(&mut (ref mut state, ref mut actions)) => {
                if space.is_goal(&state) {
                    return Some(path);
                }
                match actions.next() {
                    None => None,
                    Some(action) => {
                        let next_state = space.next_state(&state, &action);
                        let next_actions = space.actions(&next_state);
                        path.push(action);
                        Some((next_state, next_actions))
                    }
                }
            }
        };
        match result {
            None => {
                path.pop();
                frontier.pop();
            },
            Some((next_state, next_actions)) => {
                frontier.push((next_state, next_actions));
            },
        };
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::*;

    #[test]
    pub fn test_depth_first_search() {
        struct S {
            goal: i32,
        }

        #[derive(Debug, Clone, PartialEq)]
        enum Direction {
            Left,
            Right
        }

        impl SearchSpace for S {
            type State = i32;
            type Action = Direction;
            type Iterator = IntoIter<Self::Action>;

            fn actions(&self, state: &i32) -> Self::Iterator {
                if *state == 0 || *state == 1 {
                    vec![Direction::Left, Direction::Right].into_iter()
                } else {
                    vec![].into_iter()
                }
            }

            fn next_state(&self, state: &i32, action: &Direction) -> i32 {
                match *state {
                    0 => match *action {
                        Direction::Left => 1,
                        Direction::Right => 2,
                    },
                    1 => match *action {
                        Direction::Left => 3,
                        Direction::Right => 4,
                    },
                    node => node
                }
            }

            fn is_goal(&self, state: &i32) -> bool {
                return self.goal == *state
            }
        }

        impl S {
            fn solve(start: i32, goal: i32) -> Option<Vec<Direction>> {
                let space = S { goal: goal };
                depth_first_search(&space, start)
            }
        }

        assert_eq!(S::solve(0, 0).unwrap(), vec![]);
        assert_eq!(S::solve(0, 1).unwrap(), vec![Direction::Left]);
        assert_eq!(S::solve(0, 2).unwrap(), vec![Direction::Right]);
        assert_eq!(S::solve(0, 3).unwrap(), vec![Direction::Left, Direction::Left]);
        assert_eq!(S::solve(0, 4).unwrap(), vec![Direction::Left, Direction::Right]);
        assert_eq!(S::solve(2, 2).unwrap(), vec![]);
        assert!(S::solve(5, 0).is_none());
    }
}
<commit_msg>Remove Clone and Debug bounds<commit_after>use std::hash::Hash;
use std::collections::HashSet;

pub trait SearchSpace {
    type State: Ord + Hash + Eq;
    type Action;
    type Iterator: Iterator<Item=Self::Action>;

    fn actions(&self, state: &Self::State) -> Self::Iterator;
    fn next_state(&self, state: &Self::State, action: &Self::Action) -> Self::State;
    fn is_goal(&self, state: &Self::State) -> bool;
}

pub fn depth_first_search<S>(space: &S, start: S::State) -> Option<Vec<S::Action>>
where S: SearchSpace {
    let mut path = Vec::new();
    let actions = space.actions(&start);
    let mut frontier = vec![(start, actions)];

    loop {
        let result = match frontier.last_mut() {
            None => return None,
            Some(&mut (ref mut state, ref mut actions)) => {
                if space.is_goal(&state) {
                    return Some(path);
                }
                match actions.next() {
                    None => None,
                    Some(action) => {
                        let next_state = space.next_state(&state, &action);
                        let next_actions = space.actions(&next_state);
                        path.push(action);
                        Some((next_state, next_actions))
                    }
                }
            }
        };
        match result {
            None => {
                path.pop();
                frontier.pop();
            },
            Some((next_state, next_actions)) => {
                frontier.push((next_state, next_actions));
            },
        };
    }
}

#[cfg(test)]
pub mod tests {
    use std::vec::IntoIter;
    use super::*;

    #[test]
    pub fn test_depth_first_search() {
        struct S {
            goal: i32,
        }

        #[derive(Debug, Clone, PartialEq)]
        enum Direction {
            Left,
            Right
        }

        impl SearchSpace for S {
            type State = i32;
            type Action = Direction;
            type Iterator = IntoIter<Self::Action>;

            fn actions(&self, state: &i32) -> Self::Iterator {
                if *state == 0 || *state == 1 {
                    vec![Direction::Left, Direction::Right].into_iter()
                } else {
                    vec![].into_iter()
                }
            }

            fn next_state(&self, state: &i32, action: &Direction) -> i32 {
                match *state {
                    0 => match *action {
                        Direction::Left => 1,
                        Direction::Right => 2,
                    },
                    1 => match *action {
                        Direction::Left => 3,
                        Direction::Right => 4,
                    },
                    node => node
                }
            }

            fn is_goal(&self, state: &i32) -> bool {
                return self.goal == *state
            }
        }

        impl S {
            fn solve(start: i32, goal: i32) -> Option<Vec<Direction>> {
                let space = S { goal: goal };
                depth_first_search(&space, start)
            }
        }

        assert_eq!(S::solve(0, 0).unwrap(), vec![]);
        assert_eq!(S::solve(0, 1).unwrap(), vec![Direction::Left]);
        assert_eq!(S::solve(0, 2).unwrap(), vec![Direction::Right]);
        assert_eq!(S::solve(0, 3).unwrap(), vec![Direction::Left, Direction::Left]);
        assert_eq!(S::solve(0, 4).unwrap(), vec![Direction::Left, Direction::Right]);
        assert_eq!(S::solve(2, 2).unwrap(), vec![]);
        assert!(S::solve(5, 0).is_none());
    }
}
<|endoftext|>


<commit_before>use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use std::str;
use std::time::Duration;

use tokio_core::reactor::Core;
use regex::Regex;

use gateway::Gateway;
use errors::SearchError;
use async::get_control_url as get_control_url_async;

// Content of the request.
pub const SEARCH_REQUEST: &'static str = "M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

/// Search gateway, bind to all interfaces and use a timeout of 3 seconds.
///
/// Bind to all interfaces.
/// The request will timeout after 3 seconds.
pub fn search_gateway() -> Result<Gateway, SearchError> {
    search_gateway_timeout(Duration::from_secs(3))
}

/// Search gateway, bind to all interfaces and use the given duration for the timeout.
///
/// Bind to all interfaces.
/// The request will timeout after the given duration.
pub fn search_gateway_timeout(timeout: Duration) -> Result<Gateway, SearchError> {
    search_gateway_from_timeout(Ipv4Addr::new(0, 0, 0, 0), timeout)
}

/// Search gateway, bind to the given interface and use a time of 3 seconds.
///
/// Bind to the given interface.
/// The request will timeout after 3 seconds.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<Gateway, SearchError> {
    search_gateway_from_timeout(ip, Duration::from_secs(3))
}

/// Search gateway, bind to the given interface and use the given duration for the timeout.
///
/// Bind to the given interface.
/// The request will timeout after the given duration.
pub fn search_gateway_from_timeout(
    ip: Ipv4Addr,
    timeout: Duration,
) -> Result<Gateway, SearchError> {
    let addr = SocketAddrV4::new(ip, 0);
    let socket = try!(UdpSocket::bind(addr));
    try!(socket.set_read_timeout(Some(timeout)));

    try!(socket.send_to(
        SEARCH_REQUEST.as_bytes(),
        "239.255.255.250:1900",
    ));
    let mut buf = [0u8; 1024];
    let (read, _) = try!(socket.recv_from(&mut buf));
    let text = try!(str::from_utf8(&buf[..read]));

    match parse_result(text) {
        None => Err(SearchError::InvalidResponse),
        Some(location) => {
            let control_url = try!(get_control_url(&location));
            Ok(Gateway {
                addr: location.0,
                control_url: control_url,
            })
        }
    }
}

// Parse the result.
pub fn parse_result(text: &str) -> Option<(SocketAddrV4, String)> {
    let re = Regex::new(
        r"(?i:Location):\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)(/[^\r]*)",
    ).unwrap();
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = &cap[1];
                let port = &cap[2];
                return Some((
                    SocketAddrV4::new(
                        addr.parse::<Ipv4Addr>().unwrap(),
                        port.parse::<u16>().unwrap(),
                    ),
                    cap[3].to_string(),
                ));
            }
        }
    }
    None
}

fn get_control_url(location: &(SocketAddrV4, String)) -> Result<String, SearchError> {
    let mut core = Core::new()?;
    let handle = core.handle();
    core.run(get_control_url_async(location, &handle))
}

#[test]
fn test_parse_result_case_insensitivity() {
    assert!(parse_result("location:http://0.0.0.0:0/control_url").is_some());
    assert!(parse_result("LOCATION:http://0.0.0.0:0/control_url").is_some());
}

#[test]
fn test_parse_result() {
    let result = parse_result("location:http://0.0.0.0:0/control_url").unwrap();
    assert_eq!(result.0.ip(), &Ipv4Addr::new(0, 0, 0, 0));
    assert_eq!(result.0.port(), 0);
    assert_eq!(&result.1[..], "/control_url");
}
<commit_msg>Handle invalid SSDP responses from a Unifi controller <commit_after>use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use std::str;
use std::time::Duration;

use tokio_core::reactor::Core;
use regex::Regex;

use gateway::Gateway;
use errors::SearchError;
use async::get_control_url as get_control_url_async;

// Content of the request.
pub const SEARCH_REQUEST: &'static str = "M-SEARCH * HTTP/1.1\r
Host:239.255.255.250:1900\r
ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r
Man:\"ssdp:discover\"\r
MX:3\r\n\r\n";

/// Search gateway, bind to all interfaces and use a timeout of 3 seconds.
///
/// Bind to all interfaces.
/// The request will timeout after 3 seconds.
pub fn search_gateway() -> Result<Gateway, SearchError> {
    search_gateway_timeout(Duration::from_secs(3))
}

/// Search gateway, bind to all interfaces and use the given duration for the timeout.
///
/// Bind to all interfaces.
/// The request will timeout after the given duration.
pub fn search_gateway_timeout(timeout: Duration) -> Result<Gateway, SearchError> {
    search_gateway_from_timeout(Ipv4Addr::new(0, 0, 0, 0), timeout)
}

/// Search gateway, bind to the given interface and use a time of 3 seconds.
///
/// Bind to the given interface.
/// The request will timeout after 3 seconds.
pub fn search_gateway_from(ip: Ipv4Addr) -> Result<Gateway, SearchError> {
    search_gateway_from_timeout(ip, Duration::from_secs(3))
}

/// Search gateway, bind to the given interface and use the given duration for the timeout.
///
/// Bind to the given interface.
/// The request will timeout after the given duration.
pub fn search_gateway_from_timeout(
    ip: Ipv4Addr,
    timeout: Duration,
) -> Result<Gateway, SearchError> {
    let addr = SocketAddrV4::new(ip, 0);
    let socket = try!(UdpSocket::bind(addr));
    try!(socket.set_read_timeout(Some(timeout)));

    try!(socket.send_to(
        SEARCH_REQUEST.as_bytes(),
        "239.255.255.250:1900",
    ));
    loop {
        let mut buf = [0u8; 1024];
        let (read, _) = try!(socket.recv_from(&mut buf));
        let text = try!(str::from_utf8(&buf[..read]));

        match parse_result(text) {
            None => return Err(SearchError::InvalidResponse),
            Some(location) => {
                match get_control_url(&location) {
                    Ok(control_url) =>
                        return Ok(Gateway {
                            addr: location.0,
                            control_url: control_url,
                        }),
                    _ => ()
                }
            }
        }
    }
}

// Parse the result.
pub fn parse_result(text: &str) -> Option<(SocketAddrV4, String)> {
    let re = Regex::new(
        r"(?i:Location):\s*http://(\d+\.\d+\.\d+\.\d+):(\d+)(/[^\r]*)",
    ).unwrap();
    for line in text.lines() {
        match re.captures(line) {
            None => continue,
            Some(cap) => {
                // these shouldn't fail if the regex matched.
                let addr = &cap[1];
                let port = &cap[2];
                return Some((
                    SocketAddrV4::new(
                        addr.parse::<Ipv4Addr>().unwrap(),
                        port.parse::<u16>().unwrap(),
                    ),
                    cap[3].to_string(),
                ));
            }
        }
    }
    None
}

fn get_control_url(location: &(SocketAddrV4, String)) -> Result<String, SearchError> {
    let mut core = Core::new()?;
    let handle = core.handle();
    core.run(get_control_url_async(location, &handle))
}

#[test]
fn test_parse_result_case_insensitivity() {
    assert!(parse_result("location:http://0.0.0.0:0/control_url").is_some());
    assert!(parse_result("LOCATION:http://0.0.0.0:0/control_url").is_some());
}

#[test]
fn test_parse_result() {
    let result = parse_result("location:http://0.0.0.0:0/control_url").unwrap();
    assert_eq!(result.0.ip(), &Ipv4Addr::new(0, 0, 0, 0));
    assert_eq!(result.0.port(), 0);
    assert_eq!(&result.1[..], "/control_url");
}
<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {

    fn checked<T>(&self, result : sqlite3::SqliteResult<T>) -> T {
        match result {
            Err(e) => {fail!("database error: {}, {:?}", e, self.db.get_errmsg()) }
            Ok(v) => { return v; }
        }
    }

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.is_alphanumeric() { return Ok(false); }

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));
        println!("got the cursor");
        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {

        if definition.len() != word.len() { return Ok(false); }

        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d[0] == word[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {
        let mut query = StrBuf::new();
        query.push_str(format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str("; COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(query.as_slice()));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<~str> {

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<int, ~str>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row.get(&~"Definer") { &sqlite3::Text(ref t) => t.clone(), _ => fail!(), };
                    let idx = match row.get(&~"Idx") { &sqlite3::Integer(ref i) => i.clone(), _ => fail!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok(~"
this word has no definition yet
");
        } else {

            let mut result = StrBuf::new();
            result.push_str("
");
            for idx in range::<int>(0, word.len() as int) {
                let definer : &str = map.get(&idx).as_slice();
                result.push_str(format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result.into_owned());
        }
    }

}

static lookup_form : &'static str =
      r#"<form action="define" method="get">
          <input name=\"word\"/><button>go</button></form>"#;

fn define_form(word :&str) -> ~str {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\"/><button>define</button></form>", word=word)
}

enum PageData<'a> {
    NoWord,
    WordAndDef(&'a str, &'a str, Option<&'a str>),
}

fn construct_html(page_data : PageData) -> ~str {
    let mut result = StrBuf::new();
    result.push_str(format!("{}", header));
    match page_data {
        NoWord => {
            result.push_str("
 that's not a word
");
        }
        WordAndDef(word, def_div, _err) => {
            result.push_str(format!("
{}
", word));

            result.push_str(def_div);
            result.push_str(define_form(word));
        }
    }

    result.push_str(lookup_form);

    result.push_str("");
    result.into_owned()
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = match path.query.find(&~"word") {
                Some(w) if self.checked(self.is_word(*w)) => {
                    w.clone()
                }
                _ => {
                    content.get_body().set_bytes(construct_html(NoWord).as_bytes());
                    return context.done();
                }
            };

            match path.query.find(&~"definition") {
                None => {
                    let def_div = self.checked(self.get_def(word));

                    content.get_body().set_bytes(construct_html(WordAndDef(word.as_slice(),
                                                                           def_div.as_slice(),
                                                                           None)).as_bytes());
                }
                Some(def_query) => {

                    let definition : ~[&str] = def_query.split('+').collect();

                    if self.checked(self.validate_def(word, definition)) {

                        self.checked(self.write_def(word, definition));
                        let def_div = self.checked(self.get_def(word));
                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      None)).as_bytes());

                    } else {

                        let def_div = self.checked(self.get_def(word));

                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      Some("invalid definition"))).as_bytes());
                    }
                }
            }

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let args = ::std::os::args();

    if args.len() == 4 && args[1].as_slice() == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(args[2].as_slice());
        let proddb_path = ::std::path::Path::new(args[3].as_slice());
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
        println!("success!");
    }

    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>unescape<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     .err {
       font-size: 90%;
       color: #AA0000;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {

    fn checked<T>(&self, result : sqlite3::SqliteResult<T>) -> T {
        match result {
            Err(e) => {fail!("database error: {}, {:?}", e, self.db.get_errmsg()) }
            Ok(v) => { return v; }
        }
    }

    fn is_word(&self, word : &str) -> sqlite3::SqliteResult<bool> {

        if ! word.is_alphanumeric() { return Ok(false); }

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));
        println!("got the cursor");
        return Ok(try!(cursor.step_row()).is_some());
    }

    fn validate_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<bool> {

        if definition.len() != word.len() { return Ok(false); }

        let mut idx = 0;
        for &d in definition.iter() {
            if !(try!(self.is_word(d)) && d.len() > 0 && d[0] == word[idx]) {
                return Ok(false);
            }

            idx += 1;
        }

        return Ok(true);
    }

    fn write_def(&self, word : &str, definition : &[&str]) -> sqlite3::SqliteResult<()> {
        let mut query = StrBuf::new();
        query.push_str(format!("BEGIN; DELETE FROM Definitions WHERE Definee =\"{}\"; ", word));
        query.push_str("INSERT INTO Definitions(Definee, Idx, Definer) VALUES");
        let mut idx = 0;
        for &d in definition.iter() {
            if idx != 0 { query.push_str(","); }
            query.push_str(format!("(\"{}\", {}, \"{}\")", word, idx, d));
            idx += 1;
        }
        query.push_str("; COMMIT;");

        println!("query: {}", query);

        try!(self.db.exec(query.as_slice()));

        return Ok(());
    }

    fn get_def(&self, word : &str) -> sqlite3::SqliteResult<~str> {

        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Definitions WHERE Definee = \"{}\";", word),
            &None));

        let mut map = HashMap::<int, ~str>::new();

        loop {
            match try!(cursor.step_row()) {
                None => break,
                Some(row) => {
                    let definer = match row.get(&~"Definer") { &sqlite3::Text(ref t) => t.clone(), _ => fail!(), };
                    let idx = match row.get(&~"Idx") { &sqlite3::Integer(ref i) => i.clone(), _ => fail!(), };

                    map.insert(idx, definer);
                }
            }
        }

        if map.len() != word.len() {
            return Ok(~"
this word has no definition yet
");
        } else {

            let mut result = StrBuf::new();
            result.push_str("
");
            for idx in range::<int>(0, word.len() as int) {
                let definer : &str = map.get(&idx).as_slice();
                result.push_str(format!(" {word} ", word=definer));
            }
            result.push_str("
");
            return Ok(result.into_owned());
        }
    }

}

static lookup_form : &'static str =
      r#"<form action="define" method="get">
          <input name="word"/><button>go</button></form>"#;

fn define_form(word :&str) -> ~str {
       format!("<form action=\"define\" method=\"get\">
               <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
               <input name=\"definition\"/><button>define</button></form>", word=word)
}

enum PageData<'a> {
    NoWord,
    WordAndDef(&'a str, &'a str, Option<&'a str>),
}

fn construct_html(page_data : PageData) -> ~str {
    let mut result = StrBuf::new();
    result.push_str(format!("{}", header));
    match page_data {
        NoWord => {
            result.push_str("
 that's not a word
");
        }
        WordAndDef(word, def_div, _err) => {
            result.push_str(format!("
{}
", word));

            result.push_str(def_div);
            result.push_str(define_form(word));
        }
    }

    result.push_str(lookup_form);

    result.push_str("");
    result.into_owned()
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = match path.query.find(&~"word") {
                Some(w) if self.checked(self.is_word(*w)) => {
                    w.clone()
                }
                _ => {
                    content.get_body().set_bytes(construct_html(NoWord).as_bytes());
                    return context.done();
                }
            };

            match path.query.find(&~"definition") {
                None => {
                    let def_div = self.checked(self.get_def(word));

                    content.get_body().set_bytes(construct_html(WordAndDef(word.as_slice(),
                                                                           def_div.as_slice(),
                                                                           None)).as_bytes());
                }
                Some(def_query) => {

                    let definition : ~[&str] = def_query.split('+').collect();

                    if self.checked(self.validate_def(word, definition)) {

                        self.checked(self.write_def(word, definition));
                        let def_div = self.checked(self.get_def(word));
                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      None)).as_bytes());

                    } else {

                        let def_div = self.checked(self.get_def(word));

                        content.get_body().set_bytes(
                            construct_html(WordAndDef(word.as_slice(),
                                                      def_div.as_slice(),
                                                      Some("invalid definition"))).as_bytes());
                    }
                }
            }

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {

    let args = ::std::os::args();

    if args.len() == 4 && args[1].as_slice() == "--init" {
        println!("initializing...");
        let initdb_path = ::std::path::Path::new(args[2].as_slice());
        let proddb_path = ::std::path::Path::new(args[3].as_slice());
        println!("copying database from {} to {}", args[2], args[3]);
        try!(::std::io::fs::copy(&initdb_path, &proddb_path));
        println!("success!");
    }

    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut};
use std::str::{self, FromStr};
use std::net::{SocketAddr, lookup_host, SocketAddrV4};
use std::io::{Read, Write};
use std::mem;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicUsize, Ordering};
use spin::Mutex as SpinLock;
use std::collections::{HashMap, HashSet};
use std::collections::hash_state::DefaultState;
use fnv::FnvHasher;
use mio::tcp::{TcpStream, TcpListener};
use mio::util::{Slab};
use mio::{Buf, MutBuf, Token, EventLoop, Interest, PollOpt, ReadHint, Timeout, Handler, Sender};
use threadpool::ThreadPool;
use num_cpus::get as get_num_cpus;
use rustc_serialize::json;

use queue::*;
use queue_backend::Message;
use config::*;
use protocol::*;

const SERVER: Token = Token(0);
const INVALID_CLIENT: Token = Token(1);
const FIRST_CLIENT: Token = Token(2);

const BUSY_WAIT: Token = Token(1000000);

#[derive(Debug)]
pub enum NotifyMessage {
    Response(ResponseBuffer),
    Available(String),
}

struct Connection {
    stream: TcpStream,
    token: Token,
    request_buffer: RequestBuffer,
    response_buffer: Option<ResponseBuffer>,
    interest: Interest
}

struct ServerQueue {
    queue: Queue,
    waiting_flag: AtomicUsize,
    wait_list: SpinLock<HashSet<Token, DefaultState<FnvHasher>>>
}

struct ServerBackend {
    config: ServerConfig,
    queues: HashMap<String, Arc<ServerQueue>, DefaultState<FnvHasher>>,
}

pub struct Server {
    listener: TcpListener,
    state: Arc<RwLock<ServerBackend>>,
    thread_pool: ThreadPool
}

pub struct ServerHandler {
    server: Server,
    connections: Slab<Connection>,
}

struct Dispatcher {
    token: Token,
    request: RequestBuffer,
    state: Arc<RwLock<ServerBackend>>,
    sender: Sender<(Token, NotifyMessage)>
}

type ResponseResult = Result<ResponseBuffer, Status>;

impl ServerBackend {
    #[inline]
    fn get_queue(&self, name: &str) -> Option<Arc<ServerQueue>> {
        self.queues.get(name).map(|q| q.clone())
    }

    #[inline]
    fn remove_queue(&mut self, name: &str) {
        self.queues.remove(name);
        // TODO: connections on wait_list should return errors
    }

    fn get_or_create_queue(&mut self, name: &str) -> Arc<ServerQueue> {
        if let Some(q) = self.queues.get(name) {
            return q.clone()
        }
        info!("Creating queue {:?}", name);
        let inner_queue = Queue::new(self.config.new_queue_config(name), true);
        trace!("done creating queue {:?}", name);

        let queue = Arc::new(ServerQueue {
            queue: inner_queue,
            waiting_flag: Default::default(),
            wait_list: SpinLock::new(Default::default()),
        });

        self.queues.insert(name.into(), queue.clone());
        queue
    }

}

impl Dispatcher {
    fn list_queues(&self) -> String {
        let locked_state = self.state.read().unwrap();
        let queue_names: Vec<_> = locked_state.queues.keys().collect();
        json::encode(&queue_names).unwrap()
    }

    fn split_colon(composed: &str) -> (&str, Option<&str>) {
        if let Some(pos) = composed.find(":") {
            (&composed[..pos], Some(&composed[pos + 1..]))
        } else {
            (composed, None)
        }
    }

    fn get(&self, opcode: OpCode, key_str_slice: &str) -> ResponseResult {
        let (queue_name, channel_name_opt) = Self::split_colon(key_str_slice);
        let channel_name = channel_name_opt.unwrap();
        let sq_opt = self.state.read().unwrap().get_queue(queue_name);
        if let Some(sq) = sq_opt {
            if let Some(message) = sq.queue.as_mut().get(channel_name) {
                Ok(ResponseBuffer::new_get_response(&self.request, message.id, message.body))
            } else {
                debug!("queue {:?} channel {:?} has no messages", queue_name, channel_name);
                Err(Status::KeyNotFound)
            }
        } else {
            debug!("queue {:?} not found", queue_name);
            Err(Status::InvalidArguments)
        }
    }

    fn put(&self, opcode: OpCode, key_str_slice: &str, value_slice: &[u8]) -> ResponseResult {
        let (queue_name, channel_name_opt) = Self::split_colon(key_str_slice);
        let sq_opt = self.state.read().unwrap().get_queue(queue_name);
        let sq = sq_opt.unwrap_or_else(|| {
            self.state.write().unwrap().get_or_create_queue(queue_name)
        });

        if let Some(channel_name) = channel_name_opt {
            info!("creating queue {:?} channel {:?}", queue_name, channel_name);
            sq.queue.as_mut().create_channel(channel_name);
        } else {
            debug!("inserting into {:?} {:?}", key_str_slice, value_slice);
            let id = sq.queue.as_mut().put(&Message{id:0, body: value_slice}).unwrap();
            trace!("inserted message into {:?} with id {:?}", key_str_slice, id);
        }
        Ok(ResponseBuffer::new_set_response())
    }

    fn delete(&self, opcode: OpCode, key_str_slice: &str) -> ResponseResult {
        let (queue_name, _opt) = Self::split_colon(key_str_slice);
        let sq_opt = self.state.read().unwrap().get_queue(queue_name);
        let sq = if let Some(queue) = sq_opt {
            queue
        } else {
            return Err(Status::KeyNotFound)
        };

        let (command_name, id_str_opt) = Self::split_colon(_opt.unwrap());
        if command_name.starts_with('_') {
            match command_name {
                "_purge" => {
                    sq.queue.as_mut().purge();
                },
                "_delete" => {
                    sq.queue.as_mut().set_state(QueueState::Deleting);
                    self.state.write().unwrap().remove_queue(queue_name);
                },
                _ => return Err(Status::InvalidArguments)
            }
        } else if let Some(id_str) = id_str_opt {
            let channel_name = command_name;
            let id = if let Ok(id) = id_str_opt.unwrap().parse() {
                id
            } else {
                return Err(Status::InvalidArguments)
            };
            debug!("deleting message {:?} from {:?}", id, command_name);
            if sq.queue.as_mut().delete(channel_name, id).is_none() {
                return Err(Status::KeyNotFound)
            }
        } else {
            debug!("deleting channel {:?}", command_name);
            if ! sq.queue.as_mut().delete_channel(command_name) {
                return Err(Status::KeyNotFound)
            }
        }
        Ok(ResponseBuffer::new(opcode, Status::NoError))
    }

    fn dispatch(self) {
        let opcode = self.request.opcode();

        let key_str_slice = str::from_utf8(self.request.key_slice()).unwrap();
        let value_slice = self.request.value_slice();

        debug!("dispatch {:?} {:?} {:?} {:?}", self.token, opcode, key_str_slice, value_slice);

        let response_result = match opcode {
            OpCode::Get | OpCode::GetK | OpCode::GetQ | OpCode::GetKQ
            if value_slice.is_empty() && !key_str_slice.is_empty() => {
                self.get(opcode, key_str_slice)
            }
            OpCode::Set if !key_str_slice.is_empty() => {
                let r = self.put(opcode, key_str_slice, value_slice);
                r
            }
            OpCode::Delete if !key_str_slice.is_empty() && value_slice.is_empty() => {
                self.delete(opcode, key_str_slice)
            }
            OpCode::NoOp if key_str_slice.is_empty() && value_slice.is_empty() => {
                Ok(ResponseBuffer::new(opcode, Status::NoError))
            }
            _ => Err(Status::InvalidArguments)
        };

        let response = match response_result {
            Ok(response) => response,
            Err(status) => ResponseBuffer::new(opcode, status)
        };
        let composed_msg = (self.token, NotifyMessage::Response(response));
        self.sender.send(composed_msg).unwrap();
    }
}

impl Connection {
    fn new(stream: TcpStream) -> Connection {
        Connection {
            stream: stream,
            token: INVALID_CLIENT,
            request_buffer: RequestBuffer::new(),
            response_buffer: None,
            interest: Interest::all() - Interest::writable()
        }
    }

    fn readable(&mut self, server: &mut Server, event_loop: &mut EventLoop<ServerHandler>, hint: ReadHint) -> bool {
        if hint.is_hup() || hint.is_error() {
            debug!("received hint {:?} for token {:?}", hint,  self.token);
            event_loop.deregister(&self.stream).unwrap();
            return false
        }

        while let Ok(bytes_read) = self.stream.read(self.request_buffer.mut_bytes()) {
            if bytes_read == 0 {
                break
            }
            self.request_buffer.advance(bytes_read);
            trace!("filled request_buffer with {} bytes, remaining: {}", bytes_read, self.request_buffer.remaining());

            if self.request_buffer.is_complete() {
                self.interest = Interest::none();
                event_loop.reregister(&self.stream, self.token, self.interest, PollOpt::level()).unwrap();

                debug!("dispatching request {:?} for token {:?}", self.request_buffer, self.token);
                let dispatcher = Dispatcher {
                    token: self.token,
                    request: mem::replace(&mut self.request_buffer, RequestBuffer::new()),
                    state: server.state.clone(),
                    sender: event_loop.channel(),
                };
                server.thread_pool.execute(move || { dispatcher.dispatch() });
                break
            } else {
                // keep reading
            }
        }

        true
    }

    fn writable(&mut self, server: &mut Server, event_loop: &mut EventLoop<ServerHandler>) -> bool {
        let response_buffer = self.response_buffer.as_mut().expect("writable with None response_buffer");
        while let Ok(bytes_written) = self.stream.write(response_buffer.bytes()) {
            if bytes_written == 0 {
                break
            }
            response_buffer.advance(bytes_written);
            trace!("filled response_buffer with {} bytes, remaining: {}", bytes_written, response_buffer.remaining());

            if response_buffer.is_complete() {
                debug!("done sending response {:?} to token {:?}", response_buffer, self.token);
                self.interest = Interest::all() - Interest::writable();
                event_loop.reregister(&self.stream, self.token, self.interest, PollOpt::level()).unwrap();
                if response_buffer.opcode() == OpCode::Exit {
                    return false;
                }
                break
            } else {
                // keep writing
            }
        }
        true
    }

    fn notify(&mut self, server: &mut Server, event_loop: &mut EventLoop<ServerHandler>, msg: NotifyMessage) -> bool {
        match msg {
            NotifyMessage::Response(response_buffer) => {
                self.response_buffer = Some(response_buffer);
                self.interest = Interest::all() - Interest::readable();
                event_loop.reregister(&self.stream, self.token, self.interest, PollOpt::level()).unwrap();
            }
            _ => panic!("can't handle msg {:?}", msg)
        }
        true
    }
}

impl Server {
    pub fn new(config: ServerConfig) -> (ServerHandler, EventLoop<ServerHandler>) {
        let addr = SocketAddr::from_str("127.0.0.1:9797").unwrap();

        debug!("binding tcp socket to {:?}", addr);
        let listener = TcpListener::bind(&addr).unwrap();

        let num_cpus = get_num_cpus();
        let num_threads = num_cpus * 3 / 2;
        debug!("detected {} cpus, using {} threads", num_cpus, num_threads);

        let server = Server {
            listener: listener,
            state: Arc::new(RwLock::new(ServerBackend {
                config: config,
                queues: Default::default(),
            })),
            thread_pool: ThreadPool::new(num_threads)
        };

        let mut event_loop = EventLoop::new().unwrap();
        event_loop.register_opt(&server.listener, SERVER, Interest::all() - Interest::writable(), PollOpt::edge()).unwrap();

        let server_handler = ServerHandler {
            server: server,
            connections: Slab::new_starting_at(FIRST_CLIENT, 1024)
        };

        (server_handler, event_loop)
    }

    fn accept(&mut self, connections: &mut Slab<Connection>, event_loop: &mut EventLoop<ServerHandler>) -> bool {
        let (stream, connection_addr) = self.listener.accept().unwrap();
        debug!("incomming connection from {:?}", connection_addr);

        // Don't buffer output in TCP - kills latency sensitive benchmarks
        // TODO: use TCP_CORK
        stream.set_nodelay(false).unwrap();

        let connection = Connection::new(stream);

        let token = connections.insert(connection).ok().unwrap();

        connections[token].token = token;
        debug!("assigned token {:?} to client {:?}", token, connection_addr);

        event_loop.register_opt(
            &connections[token].stream, token,
            connections[token].interest,
            PollOpt::level()
        ).unwrap();
        true
    }
}

impl Handler for ServerHandler {
    type Timeout = ();
    type Message = (Token, NotifyMessage);

    #[inline]
    fn readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token, hint: ReadHint) {
        trace!("readable event for token {:?} hint {:?}", token, hint);
        let is_ok = match token {
            SERVER => self.server.accept(&mut self.connections, event_loop),
            token => if let Some(connection) = self.connections.get_mut(token) {
                connection.readable(&mut self.server, event_loop, hint)
            } else {
                trace!("token {:?} not found", token);
                false
            }
        };
        if !is_ok {
            trace!("deregistering token {:?}", token);
            self.connections.remove(token);
        }

        trace!("done readable event for token {:?}", token);
    }

    #[inline]
    fn writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        trace!("writable event for token {:?}", token);
        let is_ok = match token {
            SERVER => unreachable!(),
            token => if let Some(connection) = self.connections.get_mut(token) {
                connection.writable(&mut self.server, event_loop)
            } else {
                trace!("token {:?} not found", token);
                false
            }
        };
        if !is_ok {
            trace!("deregistering token {:?}", token);
            self.connections.remove(token);
        }
        trace!("done writable event for token {:?}", token);
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, composed_msg: Self::Message) {
        let (token, message) = composed_msg;
        trace!("notify event for token {:?} with {:?}", token, message);
        let is_ok = match token {
            SERVER => unreachable!(),
            token => if let Some(connection) = self.connections.get_mut(token) {
                connection.notify(&mut self.server, event_loop, message)
            } else {
                trace!("token {:?} not found", token);
                false
            }
        };
        if !is_ok {
            trace!("deregistering token {:?}", token);
            self.connections.remove(token);
        }
        trace!("end notify event for token {:?}", token);
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
        warn!("timeout {:?}", timeout);
    }

    fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
        panic!("interrupted");
    }
}
<commit_msg>move queue deletion logic<commit_after>use std::ops::{Deref, DerefMut};
use std::str::{self, FromStr};
use std::net::{SocketAddr, lookup_host, SocketAddrV4};
use std::io::{Read, Write};
use std::mem;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicUsize, Ordering};
use spin::Mutex as SpinLock;
use std::collections::{HashMap, HashSet};
use std::collections::hash_state::DefaultState;
use fnv::FnvHasher;
use mio::tcp::{TcpStream, TcpListener};
use mio::util::{Slab};
use mio::{Buf, MutBuf, Token, EventLoop, Interest, PollOpt, ReadHint, Timeout, Handler, Sender};
use threadpool::ThreadPool;
use num_cpus::get as get_num_cpus;
use rustc_serialize::json;

use queue::*;
use queue_backend::Message;
use config::*;
use protocol::*;

const SERVER: Token = Token(0);
const INVALID_CLIENT: Token = Token(1);
const FIRST_CLIENT: Token = Token(2);

const BUSY_WAIT: Token = Token(1000000);

#[derive(Debug)]
pub enum NotifyMessage {
    Response(ResponseBuffer),
    Available(String),
}

struct Connection {
    stream: TcpStream,
    token: Token,
    request_buffer: RequestBuffer,
    response_buffer: Option<ResponseBuffer>,
    interest: Interest
}

struct ServerQueue {
    queue: Queue,
    waiting_flag: AtomicUsize,
    wait_list: SpinLock<HashSet<Token, DefaultState<FnvHasher>>>
}

struct ServerBackend {
    config: ServerConfig,
    queues: HashMap<String, Arc<ServerQueue>, DefaultState<FnvHasher>>,
}

pub struct Server {
    listener: TcpListener,
    state: Arc<RwLock<ServerBackend>>,
    thread_pool: ThreadPool
}

pub struct ServerHandler {
    server: Server,
    connections: Slab<Connection>,
}

struct Dispatcher {
    token: Token,
    request: RequestBuffer,
    state: Arc<RwLock<ServerBackend>>,
    sender: Sender<(Token, NotifyMessage)>
}

type ResponseResult = Result<ResponseBuffer, Status>;

impl ServerBackend {
    #[inline]
    fn get_queue(&self, name: &str) -> Option<Arc<ServerQueue>> {
        self.queues.get(name).map(|q| q.clone())
    }

    #[inline]
    fn delete_queue(&mut self, name: &str) {
        if let Some(q) = self.queues.remove(name) {
            q.queue.as_mut().set_state(QueueState::Deleting);
            // TODO: connections on wait_list should return errors
        };
    }

    fn get_or_create_queue(&mut self, name: &str) -> Arc<ServerQueue> {
        if let Some(q) = self.queues.get(name) {
            return q.clone()
        }
        info!("Creating queue {:?}", name);
        let inner_queue = Queue::new(self.config.new_queue_config(name), true);
        trace!("done creating queue {:?}", name);

        let queue = Arc::new(ServerQueue {
            queue: inner_queue,
            waiting_flag: Default::default(),
            wait_list: SpinLock::new(Default::default()),
        });

        self.queues.insert(name.into(), queue.clone());
        queue
    }

}

impl Dispatcher {
    fn list_queues(&self) -> String {
        let locked_state = self.state.read().unwrap();
        let queue_names: Vec<_> = locked_state.queues.keys().collect();
        json::encode(&queue_names).unwrap()
    }

    fn split_colon(composed: &str) -> (&str, Option<&str>) {
        if let Some(pos) = composed.find(":") {
            (&composed[..pos], Some(&composed[pos + 1..]))
        } else {
            (composed, None)
        }
    }

    fn get(&self, opcode: OpCode, key_str_slice: &str) -> ResponseResult {
        let (queue_name, channel_name_opt) = Self::split_colon(key_str_slice);
        let channel_name = channel_name_opt.unwrap();
        let sq_opt = self.state.read().unwrap().get_queue(queue_name);
        if let Some(sq) = sq_opt {
            if let Some(message) = sq.queue.as_mut().get(channel_name) {
                Ok(ResponseBuffer::new_get_response(&self.request, message.id, message.body))
            } else {
                debug!("queue {:?} channel {:?} has no messages", queue_name, channel_name);
                Err(Status::KeyNotFound)
            }
        } else {
            debug!("queue {:?} not found", queue_name);
            Err(Status::InvalidArguments)
        }
    }

    fn put(&self, opcode: OpCode, key_str_slice: &str, value_slice: &[u8]) -> ResponseResult {
        let (queue_name, channel_name_opt) = Self::split_colon(key_str_slice);
        let sq_opt = self.state.read().unwrap().get_queue(queue_name);
        let sq = sq_opt.unwrap_or_else(|| {
            self.state.write().unwrap().get_or_create_queue(queue_name)
        });

        if let Some(channel_name) = channel_name_opt {
            info!("creating queue {:?} channel {:?}", queue_name, channel_name);
            sq.queue.as_mut().create_channel(channel_name);
        } else {
            debug!("inserting into {:?} {:?}", key_str_slice, value_slice);
            let id = sq.queue.as_mut().put(&Message{id:0, body: value_slice}).unwrap();
            trace!("inserted message into {:?} with id {:?}", key_str_slice, id);
        }
        Ok(ResponseBuffer::new_set_response())
    }

    fn delete(&self, opcode: OpCode, key_str_slice: &str) -> ResponseResult {
        let (queue_name, _opt) = Self::split_colon(key_str_slice);
        let sq_opt = self.state.read().unwrap().get_queue(queue_name);
        let sq = if let Some(queue) = sq_opt {
            queue
        } else {
            return Err(Status::KeyNotFound)
        };

        let (command_name, id_str_opt) = Self::split_colon(_opt.unwrap());
        if command_name.starts_with('_') {
            match command_name {
                "_purge" => {
                    sq.queue.as_mut().purge();
                },
                "_delete" => {
                    self.state.write().unwrap().delete_queue(queue_name);
                },
                _ => return Err(Status::InvalidArguments)
            }
        } else if let Some(id_str) = id_str_opt {
            let channel_name = command_name;
            let id = if let Ok(id) = id_str_opt.unwrap().parse() {
                id
            } else {
                return Err(Status::InvalidArguments)
            };
            debug!("deleting message {:?} from {:?}", id, command_name);
            if sq.queue.as_mut().delete(channel_name, id).is_none() {
                return Err(Status::KeyNotFound)
            }
        } else {
            debug!("deleting channel {:?}", command_name);
            if ! sq.queue.as_mut().delete_channel(command_name) {
                return Err(Status::KeyNotFound)
            }
        }
        Ok(ResponseBuffer::new(opcode, Status::NoError))
    }

    fn dispatch(self) {
        let opcode = self.request.opcode();

        let key_str_slice = str::from_utf8(self.request.key_slice()).unwrap();
        let value_slice = self.request.value_slice();

        debug!("dispatch {:?} {:?} {:?} {:?}", self.token, opcode, key_str_slice, value_slice);

        let response_result = match opcode {
            OpCode::Get | OpCode::GetK | OpCode::GetQ | OpCode::GetKQ
            if value_slice.is_empty() && !key_str_slice.is_empty() => {
                self.get(opcode, key_str_slice)
            }
            OpCode::Set if !key_str_slice.is_empty() => {
                let r = self.put(opcode, key_str_slice, value_slice);
                r
            }
            OpCode::Delete if !key_str_slice.is_empty() && value_slice.is_empty() => {
                self.delete(opcode, key_str_slice)
            }
            OpCode::NoOp if key_str_slice.is_empty() && value_slice.is_empty() => {
                Ok(ResponseBuffer::new(opcode, Status::NoError))
            }
            _ => Err(Status::InvalidArguments)
        };

        let response = match response_result {
            Ok(response) => response,
            Err(status) => ResponseBuffer::new(opcode, status)
        };
        let composed_msg = (self.token, NotifyMessage::Response(response));
        self.sender.send(composed_msg).unwrap();
    }
}

impl Connection {
    fn new(stream: TcpStream) -> Connection {
        Connection {
            stream: stream,
            token: INVALID_CLIENT,
            request_buffer: RequestBuffer::new(),
            response_buffer: None,
            interest: Interest::all() - Interest::writable()
        }
    }

    fn readable(&mut self, server: &mut Server, event_loop: &mut EventLoop<ServerHandler>, hint: ReadHint) -> bool {
        if hint.is_hup() || hint.is_error() {
            debug!("received hint {:?} for token {:?}", hint,  self.token);
            event_loop.deregister(&self.stream).unwrap();
            return false
        }

        while let Ok(bytes_read) = self.stream.read(self.request_buffer.mut_bytes()) {
            if bytes_read == 0 {
                break
            }
            self.request_buffer.advance(bytes_read);
            trace!("filled request_buffer with {} bytes, remaining: {}", bytes_read, self.request_buffer.remaining());

            if self.request_buffer.is_complete() {
                self.interest = Interest::none();
                event_loop.reregister(&self.stream, self.token, self.interest, PollOpt::level()).unwrap();

                debug!("dispatching request {:?} for token {:?}", self.request_buffer, self.token);
                let dispatcher = Dispatcher {
                    token: self.token,
                    request: mem::replace(&mut self.request_buffer, RequestBuffer::new()),
                    state: server.state.clone(),
                    sender: event_loop.channel(),
                };
                server.thread_pool.execute(move || { dispatcher.dispatch() });
                break
            } else {
                // keep reading
            }
        }

        true
    }

    fn writable(&mut self, server: &mut Server, event_loop: &mut EventLoop<ServerHandler>) -> bool {
        let response_buffer = self.response_buffer.as_mut().expect("writable with None response_buffer");
        while let Ok(bytes_written) = self.stream.write(response_buffer.bytes()) {
            if bytes_written == 0 {
                break
            }
            response_buffer.advance(bytes_written);
            trace!("filled response_buffer with {} bytes, remaining: {}", bytes_written, response_buffer.remaining());

            if response_buffer.is_complete() {
                debug!("done sending response {:?} to token {:?}", response_buffer, self.token);
                self.interest = Interest::all() - Interest::writable();
                event_loop.reregister(&self.stream, self.token, self.interest, PollOpt::level()).unwrap();
                if response_buffer.opcode() == OpCode::Exit {
                    return false;
                }
                break
            } else {
                // keep writing
            }
        }
        true
    }

    fn notify(&mut self, server: &mut Server, event_loop: &mut EventLoop<ServerHandler>, msg: NotifyMessage) -> bool {
        match msg {
            NotifyMessage::Response(response_buffer) => {
                self.response_buffer = Some(response_buffer);
                self.interest = Interest::all() - Interest::readable();
                event_loop.reregister(&self.stream, self.token, self.interest, PollOpt::level()).unwrap();
            }
            _ => panic!("can't handle msg {:?}", msg)
        }
        true
    }
}

impl Server {
    pub fn new(config: ServerConfig) -> (ServerHandler, EventLoop<ServerHandler>) {
        let addr = SocketAddr::from_str("127.0.0.1:9797").unwrap();

        debug!("binding tcp socket to {:?}", addr);
        let listener = TcpListener::bind(&addr).unwrap();

        let num_cpus = get_num_cpus();
        let num_threads = num_cpus * 3 / 2;
        debug!("detected {} cpus, using {} threads", num_cpus, num_threads);

        let server = Server {
            listener: listener,
            state: Arc::new(RwLock::new(ServerBackend {
                config: config,
                queues: Default::default(),
            })),
            thread_pool: ThreadPool::new(num_threads)
        };

        let mut event_loop = EventLoop::new().unwrap();
        event_loop.register_opt(&server.listener, SERVER, Interest::all() - Interest::writable(), PollOpt::edge()).unwrap();

        let server_handler = ServerHandler {
            server: server,
            connections: Slab::new_starting_at(FIRST_CLIENT, 1024)
        };

        (server_handler, event_loop)
    }

    fn accept(&mut self, connections: &mut Slab<Connection>, event_loop: &mut EventLoop<ServerHandler>) -> bool {
        let (stream, connection_addr) = self.listener.accept().unwrap();
        debug!("incomming connection from {:?}", connection_addr);

        // Don't buffer output in TCP - kills latency sensitive benchmarks
        // TODO: use TCP_CORK
        stream.set_nodelay(false).unwrap();

        let connection = Connection::new(stream);

        let token = connections.insert(connection).ok().unwrap();

        connections[token].token = token;
        debug!("assigned token {:?} to client {:?}", token, connection_addr);

        event_loop.register_opt(
            &connections[token].stream, token,
            connections[token].interest,
            PollOpt::level()
        ).unwrap();
        true
    }
}

impl Handler for ServerHandler {
    type Timeout = ();
    type Message = (Token, NotifyMessage);

    #[inline]
    fn readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token, hint: ReadHint) {
        trace!("readable event for token {:?} hint {:?}", token, hint);
        let is_ok = match token {
            SERVER => self.server.accept(&mut self.connections, event_loop),
            token => if let Some(connection) = self.connections.get_mut(token) {
                connection.readable(&mut self.server, event_loop, hint)
            } else {
                trace!("token {:?} not found", token);
                false
            }
        };
        if !is_ok {
            trace!("deregistering token {:?}", token);
            self.connections.remove(token);
        }

        trace!("done readable event for token {:?}", token);
    }

    #[inline]
    fn writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        trace!("writable event for token {:?}", token);
        let is_ok = match token {
            SERVER => unreachable!(),
            token => if let Some(connection) = self.connections.get_mut(token) {
                connection.writable(&mut self.server, event_loop)
            } else {
                trace!("token {:?} not found", token);
                false
            }
        };
        if !is_ok {
            trace!("deregistering token {:?}", token);
            self.connections.remove(token);
        }
        trace!("done writable event for token {:?}", token);
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, composed_msg: Self::Message) {
        let (token, message) = composed_msg;
        trace!("notify event for token {:?} with {:?}", token, message);
        let is_ok = match token {
            SERVER => unreachable!(),
            token => if let Some(connection) = self.connections.get_mut(token) {
                connection.notify(&mut self.server, event_loop, message)
            } else {
                trace!("token {:?} not found", token);
                false
            }
        };
        if !is_ok {
            trace!("deregistering token {:?}", token);
            self.connections.remove(token);
        }
        trace!("end notify event for token {:?}", token);
    }

    fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
        warn!("timeout {:?}", timeout);
    }

    fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
        panic!("interrupted");
    }
}
<|endoftext|>


<commit_before>use nalgebra;
use nalgebra::{Eye, Isometry3, Matrix4, PerspectiveMatrix3, ToHomogeneous, Vector3};

/// `Camera`
///
/// Data for camera manipulation. Only modelview_matrix and projection_matrix are passed to the
/// shader as uniform values.
///
#[derive(Debug)]
#[repr(C)]
pub struct Camera {
    pub modelview_matrix: [[f32; 4]; 4],
    pub projection_matrix: [[f32; 4]; 4],
    pub position: Vector3<f32>,
    pub direction: Vector3<f32>,
    pub right: Vector3<f32>,
    pub up: Vector3<f32>,
    pub pitch: f64,
    pub yaw: f64,
    pub roll: f64,
}

use std::f64::consts::FRAC_PI_2;

impl Camera {
    /// Create a new perspective `Camera` using screen_width and screen_height to calculate the
    /// aspect ratio.
    ///
    pub fn new(screen_width: f32, screen_height: f32) -> Camera {
        // Set up camera
        let projection_matrix =
            PerspectiveMatrix3::new(screen_width / screen_height, 45.0, 0.1, 1000.0);
        let projection_matrix: Matrix4<f32> = projection_matrix.to_matrix();

        let matrix: Matrix4<f32> = Eye::new_identity(4);
        let modelview_matrix_array = *matrix.as_ref();

        let camera: Camera = Camera {
            modelview_matrix: modelview_matrix_array,
            projection_matrix: *projection_matrix.as_ref(),
            position: Vector3::new(0.0f32, 1.0f32, 0.0f32),
            direction: Vector3::new(0.0f32, 0.0f32, 1.0f32),
            right: Vector3::new(1.0f32, 0.0f32, 0.0f32),
            up: Vector3::new(0.0f32, 1.0f32, 0.0f32),
            pitch: 0.0,
            yaw: 0.0,
            roll: 0.0,
        };
        camera.aim(0.0, 0.0)
    }

    /// Rotate a `Camera` in a relative direction perpendicular to the focal point.
    ///
    pub fn aim(&self, x: f64, y: f64) -> Camera {

        let factor: f64 = 0.01;
        let horizontal: f64 = self.pitch + x * factor;
        let vertical: f64 = self.yaw + y * factor;

        let direction: Vector3<f32> = Vector3::new(
	        (vertical.cos() * horizontal.sin()) as f32,
	        vertical.sin() as f32,
	        (vertical.cos() * horizontal.cos()) as f32);

        let right: Vector3<f32> = Vector3::new(
	        (horizontal - FRAC_PI_2).sin() as f32,
	        0.0f32,
	        (horizontal - FRAC_PI_2).cos() as f32);

        let up: Vector3<f32> = nalgebra::cross(&right, &direction);
        let position: Vector3<f32> = Vector3::new(self.position[0], self.position[1], self.position[2]);
        let iso3 = Isometry3::look_at_rh(&position.to_point(),
                                         &(position + direction).to_point(),
                                         &up);
        let matrix: Matrix4<f32> = iso3.to_homogeneous();

        Camera {
            modelview_matrix: *matrix.as_ref(),
            projection_matrix: self.projection_matrix,
            position: self.position,
            direction: direction,
            right: right,
            up: up,
            pitch: horizontal,
            yaw: vertical,
            roll: 0.0f64,
        }
    }

    /// Move a `Camera` backward by a specified amount.
    ///
    pub fn move_backward(&self, amount: f32) -> Camera {
        self.move_forward(-1.0 * amount)
    }

    /// Move a `Camera` forward by a specified amount.
    ///
    pub fn move_forward(&self, amount: f32) -> Camera {

        let scaled_direction: Vector3<f32> = amount * self.direction;
        let position: Vector3<f32> = self.position + scaled_direction;
        let iso3 = Isometry3::look_at_rh(&position.to_point(),
                                         &(position + self.direction).to_point(),
                                         &self.up);
        let matrix: Matrix4<f32> = iso3.to_homogeneous();
        Camera {
            modelview_matrix: *matrix.as_ref(),
            projection_matrix: self.projection_matrix,
            position: position,
            direction: self.direction,
            right: self.right,
            up: self.up,
            pitch: self.pitch,
            yaw: self.yaw,
            roll: self.roll,
        }
    }

    /// Move a `Camera` left by a specified amount.
    ///
    pub fn move_left(&self, amount: f32) -> Camera {
        self.move_right(-1.0 * amount)
    }

    /// Move a `Camera` right by a specified amount.
    ///
    pub fn move_right(&self, amount: f32) -> Camera {
        let scaled_right: Vector3<f32> = amount * self.right;
        let position: Vector3<f32> = self.position + scaled_right;
        let iso3 = Isometry3::look_at_rh(&position.to_point(),
                                         &(position + self.direction).to_point(),
                                         &self.up);
        let matrix: Matrix4<f32> = iso3.to_homogeneous();
        Camera {
            modelview_matrix: *matrix.as_ref(),
            projection_matrix: self.projection_matrix,
            position: position,
            direction: self.direction,
            right: self.right,
            up: self.up,
            pitch: self.pitch,
            yaw: self.yaw,
            roll: self.roll,
        }
    }
}
<commit_msg>Update camera.rs<commit_after>// Copyright (C) 2016 Chris Liebert

use nalgebra;
use nalgebra::{Eye, Isometry3, Matrix4, PerspectiveMatrix3, ToHomogeneous, Vector3};

/// `Camera`
///
/// Data for camera manipulation. Only modelview_matrix and projection_matrix are passed to the
/// shader as uniform values.
///
#[derive(Debug)]
#[repr(C)]
pub struct Camera {
    pub modelview_matrix: [[f32; 4]; 4],
    pub projection_matrix: [[f32; 4]; 4],
    pub position: Vector3<f32>,
    pub direction: Vector3<f32>,
    pub right: Vector3<f32>,
    pub up: Vector3<f32>,
    pub pitch: f64,
    pub yaw: f64,
    pub roll: f64,
}

use std::f64::consts::FRAC_PI_2;

impl Camera {
    /// Create a new perspective `Camera` using screen_width and screen_height to calculate the
    /// aspect ratio.
    ///
    pub fn new(screen_width: f32, screen_height: f32) -> Camera {
        // Set up camera
        let projection_matrix =
            PerspectiveMatrix3::new(screen_width / screen_height, 45.0, 0.1, 1000.0);
        let projection_matrix: Matrix4<f32> = projection_matrix.to_matrix();

        let matrix: Matrix4<f32> = Eye::new_identity(4);
        let modelview_matrix_array = *matrix.as_ref();

        let camera: Camera = Camera {
            modelview_matrix: modelview_matrix_array,
            projection_matrix: *projection_matrix.as_ref(),
            position: Vector3::new(0.0f32, 1.0f32, 0.0f32),
            direction: Vector3::new(0.0f32, 0.0f32, 1.0f32),
            right: Vector3::new(1.0f32, 0.0f32, 0.0f32),
            up: Vector3::new(0.0f32, 1.0f32, 0.0f32),
            pitch: 0.0,
            yaw: 0.0,
            roll: 0.0,
        };
        camera.aim(0.0, 0.0)
    }

    /// Rotate a `Camera` in a relative direction perpendicular to the focal point.
    ///
    pub fn aim(&self, x: f64, y: f64) -> Camera {

        let factor: f64 = 0.01;
        let horizontal: f64 = self.pitch + x * factor;
        let vertical: f64 = self.yaw + y * factor;

        let direction: Vector3<f32> = Vector3::new(
	        (vertical.cos() * horizontal.sin()) as f32,
	        vertical.sin() as f32,
	        (vertical.cos() * horizontal.cos()) as f32);

        let right: Vector3<f32> = Vector3::new(
	        (horizontal - FRAC_PI_2).sin() as f32,
	        0.0f32,
	        (horizontal - FRAC_PI_2).cos() as f32);

        let up: Vector3<f32> = nalgebra::cross(&right, &direction);
        let position: Vector3<f32> = Vector3::new(self.position[0], self.position[1], self.position[2]);
        let iso3 = Isometry3::look_at_rh(&position.to_point(),
                                         &(position + direction).to_point(),
                                         &up);
        let matrix: Matrix4<f32> = iso3.to_homogeneous();

        Camera {
            modelview_matrix: *matrix.as_ref(),
            projection_matrix: self.projection_matrix,
            position: self.position,
            direction: direction,
            right: right,
            up: up,
            pitch: horizontal,
            yaw: vertical,
            roll: 0.0f64,
        }
    }

    /// Move a `Camera` backward by a specified amount.
    ///
    pub fn move_backward(&self, amount: f32) -> Camera {
        self.move_forward(-1.0 * amount)
    }

    /// Move a `Camera` forward by a specified amount.
    ///
    pub fn move_forward(&self, amount: f32) -> Camera {

        let scaled_direction: Vector3<f32> = amount * self.direction;
        let position: Vector3<f32> = self.position + scaled_direction;
        let iso3 = Isometry3::look_at_rh(&position.to_point(),
                                         &(position + self.direction).to_point(),
                                         &self.up);
        let matrix: Matrix4<f32> = iso3.to_homogeneous();
        Camera {
            modelview_matrix: *matrix.as_ref(),
            projection_matrix: self.projection_matrix,
            position: position,
            direction: self.direction,
            right: self.right,
            up: self.up,
            pitch: self.pitch,
            yaw: self.yaw,
            roll: self.roll,
        }
    }

    /// Move a `Camera` left by a specified amount.
    ///
    pub fn move_left(&self, amount: f32) -> Camera {
        self.move_right(-1.0 * amount)
    }

    /// Move a `Camera` right by a specified amount.
    ///
    pub fn move_right(&self, amount: f32) -> Camera {
        let scaled_right: Vector3<f32> = amount * self.right;
        let position: Vector3<f32> = self.position + scaled_right;
        let iso3 = Isometry3::look_at_rh(&position.to_point(),
                                         &(position + self.direction).to_point(),
                                         &self.up);
        let matrix: Matrix4<f32> = iso3.to_homogeneous();
        Camera {
            modelview_matrix: *matrix.as_ref(),
            projection_matrix: self.projection_matrix,
            position: position,
            direction: self.direction,
            right: self.right,
            up: self.up,
            pitch: self.pitch,
            yaw: self.yaw,
            roll: self.roll,
        }
    }
}
<|endoftext|>


<commit_before>

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro because the argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: u64,
}

/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}
<commit_msg>Move more x86 instructions to the `instructions` module<commit_after>use segmentation;

/// Enable Interrupts.
pub unsafe fn enable() {
    asm!("sti");
}

/// Disable Interrupts.
pub unsafe fn disable() {
    asm!("cli");
}

/// Generate a software interrupt.
/// This is a macro because the argument needs to be an immediate.
#[macro_export]
macro_rules! int {
    ( $x:expr ) => {
        {
            asm!("int $0" :: "N" ($x));
        }
    };
}

/// A struct describing a pointer to a descriptor table (GDT / IDT).
/// This is in a format suitable for giving to 'lgdt' or 'lidt'.
#[derive(Debug)]
#[repr(C, packed)]
pub struct DescriptorTablePointer {
    /// Size of the DT.
    pub limit: u16,
    /// Pointer to the memory region containing the DT.
    pub base: u64,
}

/// Load GDT table.
pub unsafe fn lgdt(gdt: &DescriptorTablePointer) {
    asm!("lgdt ($0)" :: "r" (gdt) : "memory");
}

/// Load LDT table.
pub unsafe fn lldt(ldt: &DescriptorTablePointer) {
    asm!("lldt ($0)" :: "r" (ldt) : "memory");
}

/// Load IDT table.
pub unsafe fn lidt(idt: &DescriptorTablePointer) {
    asm!("lidt ($0)" :: "r" (idt) : "memory");
}

/// Load the task state register.
pub unsafe fn load_tss(sel: segmentation::SegmentSelector) {
    asm!("ltr $0" :: "r" (sel.bits()));
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::io::{Write, BufRead, BufReader};
use std::fs::{File, create_dir, remove_dir, metadata};
use std::io::ErrorKind::NotFound;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::default::Default;
use std::collections::BTreeMap;
use libc::pid_t;
use libc::getpid;

use super::utils::relative;

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct CGroupPath(pub String, pub PathBuf);

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Controller {
    Cpu,
    Memory,
}

#[derive(Default)]
pub struct ParsedCGroups {
    pub all_groups: Vec<Rc<CGroupPath>>,
    pub by_name: BTreeMap<String, Rc<CGroupPath>>,
}

pub struct CGroups {
    full_paths: BTreeMap<Controller, PathBuf>
}

pub fn parse_cgroups(pid: Option<pid_t>) -> Result<ParsedCGroups, String> {
    let path = pid.map(|x| format!("/proc/{}/cgroup", x))
                   .unwrap_or("/proc/self/cgroup".to_string());
    let f = try!(File::open(&path)
                 .map_err(|e| format!("Error reading cgroup: {}", e)));
    let f = BufReader::new(f);
    let mut res: ParsedCGroups = Default::default();
    for line in f.lines() {
        let line = try!(line
                       .map_err(|e| format!("Can't read CGroup file: {}", e)));
        if line.len() == 0 {
            continue;
        }
        // Line is in form of "123:ctr1[,ctr2][=folder]:/group/path"
        let mut chunks = line[..].splitn(3, ':');
        try!(chunks.next().ok_or(format!("CGroup num expected")));
        let namechunk = try!(chunks.next()
                             .ok_or(format!("CGroup name expected")));
        let mut namepair = namechunk.splitn(2, '=');
        let names = try!(namepair.next()
                         .ok_or(format!("CGroup names expected")));
        let group_name = namepair.next().unwrap_or(names).to_string();
        let group_path = Path::new(try!(chunks.next()
                                   .ok_or(format!("CGroup path expected")))
                                   .trim());
        let grp = Rc::new(CGroupPath(group_name.clone(),
                                     group_path.to_owned()));
        res.all_groups.push(grp.clone());
        for name in names.split(',') {
            if res.by_name.insert(name.to_string(), grp.clone()).is_some() {
                return Err(format!("Duplicate CGroup encountered"));
            }
        }
    }
    return Ok(res);
}

pub fn ensure_in_group(name: &String, controllers: &Vec<String>)
    -> Result<CGroups, String>
{
    let default_controllers = vec!(
        "name".to_string(),
        "cpu".to_string(),
        "cpuacct".to_string(),
        "memory".to_string(),
        "blkio".to_string(),
        );
    let controllers = if controllers.len() > 0
        { controllers } else { &default_controllers };
    debug!("Setting up cgroup {} with controllers {:?}", name, controllers);
    // TODO(tailhook) do we need to customize cgroup mount points?
    let cgroup_base = Path::new("/sys/fs/cgroup");

    let root_path = Path::new("/");

    let parent_grp = try!(parse_cgroups(Some(1)));
    let old_grp = try!(parse_cgroups(None));
    let mypid = unsafe { getpid() };
    let mut res = CGroups { full_paths: BTreeMap::new() };

    for ctr in controllers.iter() {
        let CGroupPath(ref rfolder, ref rpath) = **try!(
            parent_grp.by_name.get(ctr)
            .ok_or(format!("CGroup {} not mounted", ctr)));
        let CGroupPath(ref ofolder, ref opath) = **try!(
            old_grp.by_name.get(ctr)
            .ok_or(format!("CGroup {} not mounted", ctr)));
        if ofolder != rfolder {
            return Err(format!("Init process has CGroup hierarchy different \
                                from ours, we can't setup CGroups in any \
                                meaningful way in this case"));
        }

        // TODO(tailhook) do we need to customize nested groups?
        // TODO(tailhook) what if we *are* init process?
        let new_path = rpath.join(&name);

        if new_path == *opath {
            debug!("Already in cgroup {}:{}", ctr, new_path.display());
            continue;
        }
        let fullpath = cgroup_base.join(&ofolder).join(
            relative(&new_path, &root_path));
        if metadata(&fullpath).is_err() {
            debug!("Creating cgroup {:?}", fullpath);
            try!(create_dir(&fullpath)
                 .map_err(|e| format!("Error creating cgroup dir: {}", e)));
        } else {
            debug!("CGroup {} already exists", fullpath.display());
        }
        debug!("Adding task to cgroup {}", fullpath.display());
        try!(OpenOptions::new().write(true).open(&fullpath.join("tasks"))
             .and_then(|mut f| write!(&mut f, "{}", mypid))
             .map_err(|e| format!(
                "Error adding myself (pid: {}) to the group {:?}: {}",
                mypid, fullpath, e)));
        match &ctr[..] {
            "cpu" => {
                res.full_paths.insert(Controller::Cpu, fullpath);
            }
            "memory" => {
                res.full_paths.insert(Controller::Memory, fullpath);
            }
            _ => {}
        };
    }
    return Ok(res);
}

pub fn remove_child_cgroup(child: &str, master: &String,
    controllers: &Vec<String>)
    -> Result<(), String>
{
    // TODO(tailhook) do we need to customize cgroup mount points?
    let cgroup_base = PathBuf::from("/sys/fs/cgroup");
    let default_controllers = vec!(
        "name".to_string(),
        "cpu".to_string(),
        "cpuacct".to_string(),
        "memory".to_string(),
        "blkio".to_string(),
        );
    let controllers = if controllers.len() > 0
        { controllers } else { &default_controllers };
    debug!("Removing cgroup {}", child);

    let root_path = PathBuf::from("/");
    let parent_grp = try!(parse_cgroups(Some(1)));

    for ctr in controllers.iter() {
        let CGroupPath(ref folder, ref path) = **parent_grp.by_name.get(ctr)
            .expect("CGroups already checked");
        let fullpath = cgroup_base.join(&folder)
            .join(relative(path, &root_path))
            .join(&master).join(child);
        remove_dir(&fullpath)
            .map_err(|e| if e.kind() != NotFound {
                error!("Error removing cgroup {}: {}", fullpath.display(), e)})
            .ok();
    }
    return Ok(());
}

impl CGroups {
    pub fn set_value(&self, ctr: Controller, key: &str, value: &str)
        -> Result<(), String>
    {
        let path = try!(self.full_paths.get(&ctr)
            .ok_or(format!("Controller {:?} is not initialized", ctr)));
        File::create(&path.join(key))
            .and_then(|mut f| f.write_all(value.as_bytes()))
            .map_err(|e| format!("Can't write to cgroup path {:?}/{}: {}",
                path, key, e))
    }
}
<commit_msg>Adds a cgroup name in cgroup creation error<commit_after>use std::rc::Rc;
use std::io::{Write, BufRead, BufReader};
use std::fs::{File, create_dir, remove_dir, metadata};
use std::io::ErrorKind::NotFound;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::default::Default;
use std::collections::BTreeMap;
use libc::pid_t;
use libc::getpid;

use super::utils::relative;

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub struct CGroupPath(pub String, pub PathBuf);

#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Controller {
    Cpu,
    Memory,
}

#[derive(Default)]
pub struct ParsedCGroups {
    pub all_groups: Vec<Rc<CGroupPath>>,
    pub by_name: BTreeMap<String, Rc<CGroupPath>>,
}

pub struct CGroups {
    full_paths: BTreeMap<Controller, PathBuf>
}

pub fn parse_cgroups(pid: Option<pid_t>) -> Result<ParsedCGroups, String> {
    let path = pid.map(|x| format!("/proc/{}/cgroup", x))
                   .unwrap_or("/proc/self/cgroup".to_string());
    let f = try!(File::open(&path)
                 .map_err(|e| format!("Error reading cgroup: {}", e)));
    let f = BufReader::new(f);
    let mut res: ParsedCGroups = Default::default();
    for line in f.lines() {
        let line = try!(line
                       .map_err(|e| format!("Can't read CGroup file: {}", e)));
        if line.len() == 0 {
            continue;
        }
        // Line is in form of "123:ctr1[,ctr2][=folder]:/group/path"
        let mut chunks = line[..].splitn(3, ':');
        try!(chunks.next().ok_or(format!("CGroup num expected")));
        let namechunk = try!(chunks.next()
                             .ok_or(format!("CGroup name expected")));
        let mut namepair = namechunk.splitn(2, '=');
        let names = try!(namepair.next()
                         .ok_or(format!("CGroup names expected")));
        let group_name = namepair.next().unwrap_or(names).to_string();
        let group_path = Path::new(try!(chunks.next()
                                   .ok_or(format!("CGroup path expected")))
                                   .trim());
        let grp = Rc::new(CGroupPath(group_name.clone(),
                                     group_path.to_owned()));
        res.all_groups.push(grp.clone());
        for name in names.split(',') {
            if res.by_name.insert(name.to_string(), grp.clone()).is_some() {
                return Err(format!("Duplicate CGroup encountered"));
            }
        }
    }
    return Ok(res);
}

pub fn ensure_in_group(name: &String, controllers: &Vec<String>)
    -> Result<CGroups, String>
{
    let default_controllers = vec!(
        "name".to_string(),
        "cpu".to_string(),
        "cpuacct".to_string(),
        "memory".to_string(),
        "blkio".to_string(),
        );
    let controllers = if controllers.len() > 0
        { controllers } else { &default_controllers };
    debug!("Setting up cgroup {} with controllers {:?}", name, controllers);
    // TODO(tailhook) do we need to customize cgroup mount points?
    let cgroup_base = Path::new("/sys/fs/cgroup");

    let root_path = Path::new("/");

    let parent_grp = try!(parse_cgroups(Some(1)));
    let old_grp = try!(parse_cgroups(None));
    let mypid = unsafe { getpid() };
    let mut res = CGroups { full_paths: BTreeMap::new() };

    for ctr in controllers.iter() {
        let CGroupPath(ref rfolder, ref rpath) = **try!(
            parent_grp.by_name.get(ctr)
            .ok_or(format!("CGroup {} not mounted", ctr)));
        let CGroupPath(ref ofolder, ref opath) = **try!(
            old_grp.by_name.get(ctr)
            .ok_or(format!("CGroup {} not mounted", ctr)));
        if ofolder != rfolder {
            return Err(format!("Init process has CGroup hierarchy different \
                                from ours, we can't setup CGroups in any \
                                meaningful way in this case"));
        }

        // TODO(tailhook) do we need to customize nested groups?
        // TODO(tailhook) what if we *are* init process?
        let new_path = rpath.join(&name);

        if new_path == *opath {
            debug!("Already in cgroup {}:{}", ctr, new_path.display());
            continue;
        }
        let fullpath = cgroup_base.join(&ofolder).join(
            relative(&new_path, &root_path));
        if metadata(&fullpath).is_err() {
            debug!("Creating cgroup {:?}", fullpath);
            try!(create_dir(&fullpath)
                 .map_err(|e| format!("Error creating cgroup dir {:?}: {}",
                                      fullpath, e)));
        } else {
            debug!("CGroup {} already exists", fullpath.display());
        }
        debug!("Adding task to cgroup {}", fullpath.display());
        try!(OpenOptions::new().write(true).open(&fullpath.join("tasks"))
             .and_then(|mut f| write!(&mut f, "{}", mypid))
             .map_err(|e| format!(
                "Error adding myself (pid: {}) to the group {:?}: {}",
                mypid, fullpath, e)));
        match &ctr[..] {
            "cpu" => {
                res.full_paths.insert(Controller::Cpu, fullpath);
            }
            "memory" => {
                res.full_paths.insert(Controller::Memory, fullpath);
            }
            _ => {}
        };
    }
    return Ok(res);
}

pub fn remove_child_cgroup(child: &str, master: &String,
    controllers: &Vec<String>)
    -> Result<(), String>
{
    // TODO(tailhook) do we need to customize cgroup mount points?
    let cgroup_base = PathBuf::from("/sys/fs/cgroup");
    let default_controllers = vec!(
        "name".to_string(),
        "cpu".to_string(),
        "cpuacct".to_string(),
        "memory".to_string(),
        "blkio".to_string(),
        );
    let controllers = if controllers.len() > 0
        { controllers } else { &default_controllers };
    debug!("Removing cgroup {}", child);

    let root_path = PathBuf::from("/");
    let parent_grp = try!(parse_cgroups(Some(1)));

    for ctr in controllers.iter() {
        let CGroupPath(ref folder, ref path) = **parent_grp.by_name.get(ctr)
            .expect("CGroups already checked");
        let fullpath = cgroup_base.join(&folder)
            .join(relative(path, &root_path))
            .join(&master).join(child);
        remove_dir(&fullpath)
            .map_err(|e| if e.kind() != NotFound {
                error!("Error removing cgroup {}: {}", fullpath.display(), e)})
            .ok();
    }
    return Ok(());
}

impl CGroups {
    pub fn set_value(&self, ctr: Controller, key: &str, value: &str)
        -> Result<(), String>
    {
        let path = try!(self.full_paths.get(&ctr)
            .ok_or(format!("Controller {:?} is not initialized", ctr)));
        File::create(&path.join(key))
            .and_then(|mut f| f.write_all(value.as_bytes()))
            .map_err(|e| format!("Can't write to cgroup path {:?}/{}: {}",
                path, key, e))
    }
}
<|endoftext|>