<commit_before>use mio::*;
use mio::unix::*;
use mio::util::Slab;
use std::path::PathBuf;
use std::io::{self,Read,Write,ErrorKind};
use std::iter::repeat;
use std::thread;
use std::str::from_utf8;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::collections::HashMap;
use std::sync::mpsc;
use log;
use rustc_serialize::json::{decode,encode};
use rustc_serialize::{Encodable,Decodable,Encoder,Decoder};
use nom::{IResult,HexDisplay};

use yxorp::network::{ProxyOrder,ServerMessage};
use yxorp::network::buffer::Buffer;
use yxorp::messages::Command;

use state::{HttpProxy,TlsProxy,ConfigState};

const SERVER: Token = Token(0);

#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)]
pub enum ListenerType {
  HTTP,
  HTTPS,
  TCP
}

impl Encodable for ListenerType {
  fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
    match *self {
      ListenerType::HTTP  => e.emit_str("HTTP"),
      ListenerType::HTTPS => e.emit_str("HTTPS"),
      ListenerType::TCP   => e.emit_str("TCP"),
    }
  }
}

impl Decodable for ListenerType {
  fn decode<D: Decoder>(decoder: &mut D) -> Result<ListenerType, D::Error> {
    let tag = try!(decoder.read_str());
    match &tag[..] {
      "HTTP"  => Ok(ListenerType::HTTP),
      "HTTPS" => Ok(ListenerType::HTTPS),
      "TCP"   => Ok(ListenerType::TCP),
      _       => Err(decoder.error("unrecognized listener type"))
    }
  }
}

pub struct Listener {
  pub tag:           String,
  pub listener_type: ListenerType,
  pub sender:        Sender<ProxyOrder>,
  pub receiver:      mpsc::Receiver<ServerMessage>,
  pub state:         ConfigState,
}

impl Listener {
  pub fn new(tag: String, listener_type: ListenerType, ip_address: String, port: u16, sender: Sender<ProxyOrder>, receiver: mpsc::Receiver<ServerMessage>) -> Listener {
    let state = match listener_type {
      ListenerType::HTTP  => ConfigState::Http(HttpProxy::new(ip_address, port)),
      ListenerType::HTTPS => ConfigState::Tls(TlsProxy::new(ip_address, port)),
      _                   => unimplemented!(),
    };

    Listener {
      tag:           tag,
      listener_type: listener_type,
      sender:        sender,
      receiver:      receiver,
      state:         state,
    }
  }
}

impl Encodable for Listener {
  fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
    e.emit_map(3, |e| {
      try!(e.emit_map_elt_key(0, |e| "tag".encode(e)));
      try!(e.emit_map_elt_val(0, |e| self.tag.encode(e)));
      try!(e.emit_map_elt_key(1, |e| "listener_type".encode(e)));
      try!(e.emit_map_elt_val(1, |e| self.listener_type.encode(e)));
      try!(e.emit_map_elt_key(2, |e| "state".encode(e)));
      try!(e.emit_map_elt_val(2, |e| self.state.encode(e)));
      Ok(())
    })
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct ConfigMessage {
    pub id:       String,
    pub listener: String,
    pub command:  Command
}

struct CommandClient {
  sock:        UnixStream,
  buf:         Buffer,
  back_buf:    Buffer,
  token:       Option<Token>,
  message_ids: Vec<String>,
}

impl CommandClient {
  fn new(sock: UnixStream) -> CommandClient {
    CommandClient {
      sock:        sock,
      buf:         Buffer::with_capacity(1024),
      back_buf:    Buffer::with_capacity(10000),
      token:       None,
      message_ids: Vec::new(),
    }
  }

  fn add_message_id(&mut self, id: String) {
    self.message_ids.push(id);
    self.message_ids.sort();
  }

  fn has_message_id(&self, id: &String) ->Option<usize> {
    self.message_ids.binary_search(&id).ok()
  }

  fn remove_message_id(&mut self, index: usize) {
    self.message_ids.remove(index);
  }

  fn reregister(&self,  event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::level() | PollOpt::oneshot());
  }

  fn conn_readable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) -> Option<Vec<ConfigMessage>>{
    trace!("server conn readable; tok={:?}", tok);
    match self.sock.read(self.buf.space()) {
      Ok(0) => {
        self.reregister(event_loop, tok);
        return None;
      },
      Err(e) => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      Ok(r) => {
        self.buf.fill(r);
        debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.as_usize(), r, from_utf8(self.buf.data()));
      },
    };

    let mut res: Option<Vec<ConfigMessage>> = None;
    let mut offset = 0usize;
    match parse(self.buf.data()) {
      IResult::Incomplete(_) => {
        return Some(Vec::new());
      },
      IResult::Error(e)      => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      IResult::Done(i, v)    => {
        offset = self.buf.data().offset(i);
        res = Some(v);
      }
    }
    debug!("parsed {} bytes, result: {:?}", offset, res);
    self.buf.consume(offset);
    return res;
  }

  fn conn_writable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    trace!("server conn writable; tok={:?}", tok);
    match self.sock.write(self.back_buf.data()) {
      Ok(0) => {},
      Ok(r) => {
        self.back_buf.consume(r);
      },
      Err(e) => log!(log::LogLevel::Error,"UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e),
    }
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::level() | PollOpt::oneshot());
  }
}

fn parse(input: &[u8]) -> IResult<&[u8], Vec<ConfigMessage>> {
  many0!(input,
    complete!(terminated!(map_res!(map_res!(is_not!("\0"), from_utf8), decode), char!('\0')))
  )
}

struct CommandServer {
  sock:  UnixListener,
  conns: Slab<CommandClient>,
  listeners: HashMap<String, Listener>,
}

impl CommandServer {
  fn accept(&mut self, event_loop: &mut EventLoop<CommandServer>) -> io::Result<()> {
    debug!("server accepting socket");

    let sock = self.sock.accept().unwrap().unwrap();
    let conn = CommandClient::new(sock);
    let tok = self.conns.insert(conn)
      .ok().expect("could not add connection to slab");

    // Register the connection
    self.conns[tok].token = Some(tok);
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.conns[tok].sock, tok, interest, PollOpt::level())
      .ok().expect("could not register socket with event loop");

    let accept_interest = EventSet::readable();
    event_loop.reregister(&self.sock, SERVER, accept_interest, PollOpt::level());
    Ok(())
  }

  fn conn<'a>(&'a mut self, tok: Token) -> &'a mut CommandClient {
    &mut self.conns[tok]
  }

  fn dispatch(&mut self, token: Token, v: Vec<ConfigMessage>) {
    for message in &v {
      let command = message.command.clone();
      if let Some(ref mut listener) = self.listeners.get_mut (&message.listener) {
        if message.command == Command::DumpConfiguration {
          self.conns[token].back_buf.write(&encode(*listener).unwrap().into_bytes());
          self.conns[token].back_buf.write(&b"\0"[..]);
        } else {
          self.conns[token].add_message_id(message.id.clone());
          listener.state.handle_command(&command);
          listener.sender.send(ProxyOrder::Command(message.id.clone(), command));
        }
      } else {
        log!(log::LogLevel::Error, "no listener found for tag: {}", message.listener);
      }
    }
  }

  fn new(srv: UnixListener, listeners: HashMap<String, Listener>) -> CommandServer {
    CommandServer {
      sock:  srv,
      conns: Slab::new_starting_at(Token(1), 128),
      listeners: listeners,
    }
  }
}

impl Handler for CommandServer {
	type Timeout = usize;
	type Message = ();

	fn ready(&mut self, event_loop: &mut EventLoop<CommandServer>, token: Token, events: EventSet) {
    //trace!("ready: {:?} -> {:?}", token, events);
    if events.is_readable() {
      match token {
        SERVER => self.accept(event_loop).unwrap(),
        _      => {
          if self.conns.contains(token) {
            let opt_v = self.conns[token].conn_readable(event_loop, token);
            if let Some(v) = opt_v {
              self.dispatch(token, v);
            }
          }
        }
      };
    }

    if events.is_writable() {
      match token {
        SERVER => panic!("received writable for token 0"),
        _      => {
          if self.conns.contains(token) {
            self.conns[token].conn_writable(event_loop, token)
          }
        }
      };
    }

    if events.is_hup() {
      if self.conns.contains(token) {
        event_loop.deregister(&self.conns[token].sock);
        self.conns.remove(token);
        trace!("closed client [{}]", token.as_usize());
      }
    }
  }

  fn notify(&mut self, event_loop: &mut EventLoop<Self>, message: Self::Message) {
    // TODO: dispatch here to clients the list of messages you want to display
    info!("notify");
  }

  fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
    for listener in self.listeners.values() {
      while let Ok(msg) = listener.receiver.try_recv() {
        println!("got msg: {:?}", msg);
        for client in self.conns.iter_mut() {
          if let Some(index) = client.has_message_id(&msg.id) {
            client.back_buf.write(&encode(&msg).unwrap().into_bytes());
            client.back_buf.write(&b"\0"[..]);
            client.remove_message_id(index);
          }
        }
      }
    }
    event_loop.timeout_ms(0, 700);
  }

}

pub fn start(path: String, listeners: HashMap<String, Listener>) {
  thread::spawn(move || {
    let mut event_loop = EventLoop::new().unwrap();
    let addr = PathBuf::from(path);
    if let Err(e) = fs::remove_file(&addr) {
      match e.kind() {
        ErrorKind::NotFound => {},
        _ => {
          log!(log::LogLevel::Error, "could not delete previous socket at {:?}: {:?}", addr, e);
          return;
        }
      }
    }
    match UnixListener::bind(&addr) {
      Ok(srv) => {
        if let Err(e) =  fs::set_permissions(&addr, fs::Permissions::from_mode(0o600)) {
          log!( log::LogLevel::Error, "could not set the unix socket permissions: {:?}", e);
          fs::remove_file(&addr);
          return;
        }
        info!("listen for connections");
        event_loop.register(&srv, SERVER, EventSet::readable(), PollOpt::level() | PollOpt::oneshot()).unwrap();
        event_loop.timeout_ms(0, 700);

        event_loop.run(&mut CommandServer::new(srv, listeners)).unwrap()
      },
      Err(e) => {
        log!(log::LogLevel::Error, "could not create unix socket: {:?}", e);
      }
    }
  });
}

#[cfg(test)]
mod tests {
  use super::*;
  use rustc_serialize::json;
  use yxorp::messages::{Command,HttpFront};

  #[test]
  fn config_message_test() {
    let raw_json = r#"{ "id": "ID_TEST", "listener": "HTTP", "command":{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "port": 4242}} }"#;
    let config: ConfigMessage = json::decode(raw_json).unwrap();
    println!("{:?}", config);
    assert_eq!(config.listener, "HTTP");
    assert_eq!(config.command, Command::AddHttpFront(HttpFront{
      app_id: String::from("xxx"),
      hostname: String::from("yyy"),
      path_begin: String::from("xxx"),
      port: 4242
    }));
  }
}
<commit_msg>Add timeouts on writable events for the config socket<commit_after>use mio::*;
use mio::unix::*;
use mio::util::Slab;
use std::path::PathBuf;
use std::io::{self,Read,Write,ErrorKind};
use std::iter::repeat;
use std::thread;
use std::str::from_utf8;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use std::collections::HashMap;
use std::sync::mpsc;
use log;
use rustc_serialize::json::{decode,encode};
use rustc_serialize::{Encodable,Decodable,Encoder,Decoder};
use nom::{IResult,HexDisplay};

use yxorp::network::{ProxyOrder,ServerMessage};
use yxorp::network::buffer::Buffer;
use yxorp::messages::Command;

use state::{HttpProxy,TlsProxy,ConfigState};

const SERVER: Token = Token(0);

#[derive(Debug,Clone,Copy,PartialEq,Eq,Hash)]
pub enum ListenerType {
  HTTP,
  HTTPS,
  TCP
}

impl Encodable for ListenerType {
  fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
    match *self {
      ListenerType::HTTP  => e.emit_str("HTTP"),
      ListenerType::HTTPS => e.emit_str("HTTPS"),
      ListenerType::TCP   => e.emit_str("TCP"),
    }
  }
}

impl Decodable for ListenerType {
  fn decode<D: Decoder>(decoder: &mut D) -> Result<ListenerType, D::Error> {
    let tag = try!(decoder.read_str());
    match &tag[..] {
      "HTTP"  => Ok(ListenerType::HTTP),
      "HTTPS" => Ok(ListenerType::HTTPS),
      "TCP"   => Ok(ListenerType::TCP),
      _       => Err(decoder.error("unrecognized listener type"))
    }
  }
}

pub struct Listener {
  pub tag:           String,
  pub listener_type: ListenerType,
  pub sender:        Sender<ProxyOrder>,
  pub receiver:      mpsc::Receiver<ServerMessage>,
  pub state:         ConfigState,
}

impl Listener {
  pub fn new(tag: String, listener_type: ListenerType, ip_address: String, port: u16, sender: Sender<ProxyOrder>, receiver: mpsc::Receiver<ServerMessage>) -> Listener {
    let state = match listener_type {
      ListenerType::HTTP  => ConfigState::Http(HttpProxy::new(ip_address, port)),
      ListenerType::HTTPS => ConfigState::Tls(TlsProxy::new(ip_address, port)),
      _                   => unimplemented!(),
    };

    Listener {
      tag:           tag,
      listener_type: listener_type,
      sender:        sender,
      receiver:      receiver,
      state:         state,
    }
  }
}

impl Encodable for Listener {
  fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> {
    e.emit_map(3, |e| {
      try!(e.emit_map_elt_key(0, |e| "tag".encode(e)));
      try!(e.emit_map_elt_val(0, |e| self.tag.encode(e)));
      try!(e.emit_map_elt_key(1, |e| "listener_type".encode(e)));
      try!(e.emit_map_elt_val(1, |e| self.listener_type.encode(e)));
      try!(e.emit_map_elt_key(2, |e| "state".encode(e)));
      try!(e.emit_map_elt_val(2, |e| self.state.encode(e)));
      Ok(())
    })
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct ConfigMessage {
    pub id:       String,
    pub listener: String,
    pub command:  Command
}

struct CommandClient {
  sock:        UnixStream,
  buf:         Buffer,
  back_buf:    Buffer,
  token:       Option<Token>,
  message_ids: Vec<String>,
  write_timeout: Option<Timeout>,
}

impl CommandClient {
  fn new(sock: UnixStream) -> CommandClient {
    CommandClient {
      sock:        sock,
      buf:         Buffer::with_capacity(1024),
      back_buf:    Buffer::with_capacity(10000),
      token:       None,
      message_ids: Vec::new(),
      write_timeout: None,
    }
  }

  fn add_message_id(&mut self, id: String) {
    self.message_ids.push(id);
    self.message_ids.sort();
  }

  fn has_message_id(&self, id: &String) ->Option<usize> {
    self.message_ids.binary_search(&id).ok()
  }

  fn remove_message_id(&mut self, index: usize) {
    self.message_ids.remove(index);
  }

  fn reregister(&self,  event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::edge() | PollOpt::oneshot());
  }

  fn conn_readable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) -> Option<Vec<ConfigMessage>>{
    trace!("server conn readable; tok={:?}", tok);
    match self.sock.read(self.buf.space()) {
      Ok(0) => {
        self.reregister(event_loop, tok);
        return None;
      },
      Err(e) => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      Ok(r) => {
        self.buf.fill(r);
        debug!("UNIX CLIENT[{}] sent {} bytes: {:?}", tok.as_usize(), r, from_utf8(self.buf.data()));
      },
    };

    let mut res: Option<Vec<ConfigMessage>> = None;
    let mut offset = 0usize;
    match parse(self.buf.data()) {
      IResult::Incomplete(_) => {
        return Some(Vec::new());
      },
      IResult::Error(e)      => {
        log!(log::LogLevel::Error, "UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e);
        return None;
      },
      IResult::Done(i, v)    => {
        offset = self.buf.data().offset(i);
        res = Some(v);
      }
    }
    debug!("parsed {} bytes, result: {:?}", offset, res);
    self.buf.consume(offset);
    return res;
  }

  fn conn_writable(&mut self, event_loop: &mut EventLoop<CommandServer>, tok: Token) {
    if self.write_timeout.is_some() {
      trace!("server conn writable; tok={:?}; waiting for timeout", tok.as_usize());
      return;
    }

    trace!("server conn writable; tok={:?}", tok);
    match self.sock.write(self.back_buf.data()) {
      Ok(0) => {
        //println!("[{}] setting timeout!", tok.as_usize());
        self.write_timeout = event_loop.timeout_ms(self.token.unwrap().as_usize(), 700).ok();
      },
      Ok(r) => {
        self.back_buf.consume(r);
      },
      Err(e) => log!(log::LogLevel::Error,"UNIX CLIENT[{}] read error: {:?}", tok.as_usize(), e),
    }
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.sock, tok, interest, PollOpt::edge() | PollOpt::oneshot());
  }
}

fn parse(input: &[u8]) -> IResult<&[u8], Vec<ConfigMessage>> {
  many0!(input,
    complete!(terminated!(map_res!(map_res!(is_not!("\0"), from_utf8), decode), char!('\0')))
  )
}

struct CommandServer {
  sock:  UnixListener,
  conns: Slab<CommandClient>,
  listeners: HashMap<String, Listener>,
}

impl CommandServer {
  fn accept(&mut self, event_loop: &mut EventLoop<CommandServer>) -> io::Result<()> {
    debug!("server accepting socket");

    let sock = self.sock.accept().unwrap().unwrap();
    let conn = CommandClient::new(sock);
    let tok = self.conns.insert(conn)
      .ok().expect("could not add connection to slab");

    // Register the connection
    self.conns[tok].token = Some(tok);
    let mut interest = EventSet::hup();
    interest.insert(EventSet::readable());
    interest.insert(EventSet::writable());
    event_loop.register(&self.conns[tok].sock, tok, interest, PollOpt::edge())
      .ok().expect("could not register socket with event loop");

    let accept_interest = EventSet::readable();
    event_loop.reregister(&self.sock, SERVER, accept_interest, PollOpt::edge());
    Ok(())
  }

  fn conn<'a>(&'a mut self, tok: Token) -> &'a mut CommandClient {
    &mut self.conns[tok]
  }

  fn dispatch(&mut self, token: Token, v: Vec<ConfigMessage>) {
    for message in &v {
      let command = message.command.clone();
      if let Some(ref mut listener) = self.listeners.get_mut (&message.listener) {
        if message.command == Command::DumpConfiguration {
          self.conns[token].back_buf.write(&encode(*listener).unwrap().into_bytes());
          self.conns[token].back_buf.write(&b"\0"[..]);
        } else {
          self.conns[token].add_message_id(message.id.clone());
          listener.state.handle_command(&command);
          listener.sender.send(ProxyOrder::Command(message.id.clone(), command));
        }
      } else {
        log!(log::LogLevel::Error, "no listener found for tag: {}", message.listener);
      }
    }
  }

  fn new(srv: UnixListener, listeners: HashMap<String, Listener>) -> CommandServer {
    CommandServer {
      sock:  srv,
      conns: Slab::new_starting_at(Token(1), 128),
      listeners: listeners,
    }
  }
}

impl Handler for CommandServer {
	type Timeout = usize;
	type Message = ();

	fn ready(&mut self, event_loop: &mut EventLoop<CommandServer>, token: Token, events: EventSet) {
    //trace!("ready: {:?} -> {:?}", token, events);
    if events.is_readable() {
      match token {
        SERVER => self.accept(event_loop).unwrap(),
        _      => {
          if self.conns.contains(token) {
            let opt_v = self.conns[token].conn_readable(event_loop, token);
            if let Some(v) = opt_v {
              self.dispatch(token, v);
            }
          }
        }
      };
    }

    if events.is_writable() {
      match token {
        SERVER => panic!("received writable for token 0"),
        _      => {
          if self.conns.contains(token) {
            self.conns[token].conn_writable(event_loop, token)
          }
        }
      };
    }

    if events.is_hup() {
      if self.conns.contains(token) {
        event_loop.deregister(&self.conns[token].sock);
        self.conns.remove(token);
        trace!("closed client [{}]", token.as_usize());
      }
    }
  }

  fn notify(&mut self, event_loop: &mut EventLoop<Self>, message: Self::Message) {
    // TODO: dispatch here to clients the list of messages you want to display
    info!("notify");
  }

  fn timeout(&mut self, event_loop: &mut EventLoop<Self>, timeout: Self::Timeout) {
    if timeout == 0 {
      for listener in self.listeners.values() {
        while let Ok(msg) = listener.receiver.try_recv() {
          //println!("got msg: {:?}", msg);
          for client in self.conns.iter_mut() {
            if let Some(index) = client.has_message_id(&msg.id) {
              client.back_buf.write(&encode(&msg).unwrap().into_bytes());
              client.back_buf.write(&b"\0"[..]);
              client.remove_message_id(index);
            }
          }
        }
      }
      event_loop.timeout_ms(0, 700);
    } else {
      let token = Token(timeout);
      if self.conns.contains(token) {
        //println!("[{}] timeout ended, registering for writes", timeout);
        self.conns[token].write_timeout = None;
        let mut interest = EventSet::hup();
        interest.insert(EventSet::readable());
        interest.insert(EventSet::writable());
        event_loop.register(&self.conns[token].sock, token, interest, PollOpt::edge() | PollOpt::oneshot());
      }
    }
  }

}

pub fn start(path: String, listeners: HashMap<String, Listener>) {
  thread::spawn(move || {
    let mut event_loop = EventLoop::new().unwrap();
    let addr = PathBuf::from(path);
    if let Err(e) = fs::remove_file(&addr) {
      match e.kind() {
        ErrorKind::NotFound => {},
        _ => {
          log!(log::LogLevel::Error, "could not delete previous socket at {:?}: {:?}", addr, e);
          return;
        }
      }
    }
    match UnixListener::bind(&addr) {
      Ok(srv) => {
        if let Err(e) =  fs::set_permissions(&addr, fs::Permissions::from_mode(0o600)) {
          log!( log::LogLevel::Error, "could not set the unix socket permissions: {:?}", e);
          fs::remove_file(&addr);
          return;
        }
        info!("listen for connections");
        event_loop.register(&srv, SERVER, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot()).unwrap();
        event_loop.timeout_ms(0, 700);

        event_loop.run(&mut CommandServer::new(srv, listeners)).unwrap()
      },
      Err(e) => {
        log!(log::LogLevel::Error, "could not create unix socket: {:?}", e);
      }
    }
  });
}

#[cfg(test)]
mod tests {
  use super::*;
  use rustc_serialize::json;
  use yxorp::messages::{Command,HttpFront};

  #[test]
  fn config_message_test() {
    let raw_json = r#"{ "id": "ID_TEST", "listener": "HTTP", "command":{"type": "ADD_HTTP_FRONT", "data": {"app_id": "xxx", "hostname": "yyy", "path_begin": "xxx", "port": 4242}} }"#;
    let config: ConfigMessage = json::decode(raw_json).unwrap();
    println!("{:?}", config);
    assert_eq!(config.listener, "HTTP");
    assert_eq!(config.command, Command::AddHttpFront(HttpFront{
      app_id: String::from("xxx"),
      hostname: String::from("yyy"),
      path_begin: String::from("xxx"),
      port: 4242
    }));
  }
}
<|endoftext|>


<commit_before>// Brief implementation of the 'node-google'
// node.js package.
use std::io::Read;

use super::hyper::Client;
use super::hyper::header::Connection;

use super::select::document::Document;
use super::select::predicate::Class;
use super::select::predicate::Name;
use super::select::predicate::And;

use super::regex::Regex;

#[derive(Debug)]
pub struct GoogleResult {
    pub link: String,
}

impl GoogleResult {
    pub fn new(link: &str) -> Self {
        GoogleResult { link: String::from(link) }
    }
}

#[derive(Debug)]
pub struct Google {
    per_page: usize,
    client: Client,
}

impl Default for Google {
    fn default() -> Self {
        Google {
            per_page: 10,
            client: Client::new(),
        }
    }
}

impl Google {
    pub fn google(&self, query: &str) -> Vec<GoogleResult> {
        let body = self.request(query);
        self.get_links(&body)
    }

    pub fn per_page(&self) -> usize {
        self.per_page
    }

    fn request(&self, query: &str) -> String {
        let url = format!("https://www.google.\
                           com/search?hl=en&q={}&start=0&sa=N&num={}&ie=UTF-8&oe=UTF-8&gws_rd=ssl",
                          query,
                          self.per_page);

        let mut res = self.client
                          .get(&url)
                          .header(Connection::close())
                          .send()
                          .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }

    fn get_links(&self, body: &str) -> Vec<GoogleResult> {
        let doc = Document::from(body);

        let item_selector = And(Name("div"), Class("g"));
        let link_container_selector = And(Name("h3"), Class("r"));
        let link_selector = Name("a");
        let cleaning_regex = Regex::new(r"(/url\?q=)(?P<link>.*)&(sa=.*&?)(ved=.*&?)(usg=.*&?)")
                                 .unwrap();

        let mut results = Vec::new();

        for item in doc.find(item_selector).iter().take(self.per_page) {
            let link_container;
            match item.find(link_container_selector).first() {
                Some(container) => {
                    link_container = container;
                }
                None => {
                    continue;
                }
            };

            let link_node = link_container.find(link_selector).first().unwrap();
            let link_href = link_node.attr("href").unwrap();

            if link_href.contains("/search?q=") {
                continue;
            }

            let clean_link = cleaning_regex.captures(&link_href)
                                           .unwrap()
                                           .name("link")
                                           .unwrap();

            results.push(GoogleResult::new(&clean_link));
        }

        results
    }
}

#[test]
fn google_works() {
    let google = Google::default();
    let results = google.google("rust lang testing");

    assert_eq!(results.len(), google.per_page());
    assert!(results.iter().any(|r| r.link == "https://doc.rust-lang.org/book/testing.html"));
}
<commit_msg>Fixed optimistic unwrap crash.<commit_after>// Brief implementation of the 'node-google'
// node.js package.
use std::io::Read;

use super::hyper::Client;
use super::hyper::header::Connection;

use super::select::document::Document;
use super::select::predicate::Class;
use super::select::predicate::Name;
use super::select::predicate::And;

use super::regex::Regex;

#[derive(Debug)]
pub struct GoogleResult {
    pub link: String,
}

impl GoogleResult {
    pub fn new(link: &str) -> Self {
        GoogleResult { link: String::from(link) }
    }
}

#[derive(Debug)]
pub struct Google {
    per_page: usize,
    client: Client,
}

impl Default for Google {
    fn default() -> Self {
        Google {
            per_page: 10,
            client: Client::new(),
        }
    }
}

impl Google {
    pub fn google(&self, query: &str) -> Vec<GoogleResult> {
        let body = self.request(query);
        self.get_links(&body)
    }

    pub fn per_page(&self) -> usize {
        self.per_page
    }

    fn request(&self, query: &str) -> String {
        let url = format!("https://www.google.\
                           com/search?hl=en&q={}&start=0&sa=N&num={}&ie=UTF-8&oe=UTF-8&gws_rd=ssl",
                          query,
                          self.per_page);

        let mut res = self.client
                          .get(&url)
                          .header(Connection::close())
                          .send()
                          .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }

    fn get_links(&self, body: &str) -> Vec<GoogleResult> {
        let doc = Document::from(body);

        let item_selector = And(Name("div"), Class("g"));
        let link_container_selector = And(Name("h3"), Class("r"));
        let link_selector = Name("a");
        let cleaning_regex = Regex::new(r"(/url\?q=)(?P<link>.*)&(sa=.*&?)(ved=.*&?)(usg=.*&?)")
                                 .unwrap();

        let mut results = Vec::new();

        for item in doc.find(item_selector).iter().take(self.per_page) {
            let link_container;
            match item.find(link_container_selector).first() {
                Some(container) => {
                    link_container = container;
                }
                None => {
                    continue;
                }
            };

            let link_node = link_container.find(link_selector).first().unwrap();
            let link_href = link_node.attr("href").unwrap();

            if link_href.contains("/search?q=") {
                continue;
            }

            let captures = cleaning_regex.captures(&link_href);
            let clean_link: &str;

            match captures {
                Some(cap) => {
                    clean_link = cap.name("link").unwrap();
                }
                None => continue,
            }

            results.push(GoogleResult::new(&clean_link));
        }

        results
    }
}

#[test]
fn google_works() {
    let google = Google::default();
    let results = google.google("rust lang testing");

    assert_eq!(results.len(), google.per_page());
    assert!(results.iter().any(|r| r.link == "https://doc.rust-lang.org/book/testing.html"));
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-pretty

use std::str;
use std::slice;

static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
static TABLE_SIZE: uint = 2 << 16;

static OCCURRENCES: [&'static str, ..5] = [
    "GGT",
    "GGTA",
    "GGTATT",
    "GGTATTTTAATT",
    "GGTATTTTAATTTATAGT",
];

// Code implementation

#[deriving(Eq, Ord, TotalOrd, TotalEq)]
struct Code(u64);

impl Code {
    fn hash(&self) -> u64 {
        let Code(ret) = *self;
        return ret;
    }

    fn push_char(&self, c: u8) -> Code {
        Code((self.hash() << 2) + (pack_symbol(c) as u64))
    }

    fn rotate(&self, c: u8, frame: i32) -> Code {
        Code(self.push_char(c).hash() & ((1u64 << (2 * (frame as u64))) - 1))
    }

    fn pack(string: &str) -> Code {
        string.bytes().fold(Code(0u64), |a, b| a.push_char(b))
    }

    // FIXME: Inefficient.
    fn unpack(&self, frame: i32) -> ~str {
        let mut key = self.hash();
        let mut result = Vec::new();
        for _ in range(0, frame) {
            result.push(unpack_symbol((key as u8) & 3));
            key >>= 2;
        }

        result.reverse();
        str::from_utf8_owned(result.move_iter().collect()).unwrap()
    }
}

// Hash table implementation

trait TableCallback {
    fn f(&self, entry: &mut Entry);
}

struct BumpCallback;

impl TableCallback for BumpCallback {
    fn f(&self, entry: &mut Entry) {
        entry.count += 1;
    }
}

struct PrintCallback(&'static str);

impl TableCallback for PrintCallback {
    fn f(&self, entry: &mut Entry) {
        let PrintCallback(s) = *self;
        println!("{}\t{}", entry.count as int, s);
    }
}

struct Entry {
    code: Code,
    count: i32,
    next: Option<~Entry>,
}

struct Table {
    count: i32,
    items: Vec<Option<~Entry>> }

struct Items<'a> {
    cur: Option<&'a Entry>,
    items: slice::Items<'a, Option<~Entry>>,
}

impl Table {
    fn new() -> Table {
        Table {
            count: 0,
            items: Vec::from_fn(TABLE_SIZE, |_| None),
        }
    }

    fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
        match item.next {
            None => {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                item.next = Some(entry);
            }
            Some(ref mut entry) => {
                if entry.code == key {
                    c.f(*entry);
                    return;
                }

                Table::search_remainder(*entry, key, c)
            }
        }
    }

    fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
        let index = key.hash() % (TABLE_SIZE as u64);

        {
            if self.items.get(index as uint).is_none() {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                *self.items.get_mut(index as uint) = Some(entry);
                return;
            }
        }

        {
            let entry = &mut *self.items.get_mut(index as uint).get_mut_ref();
            if entry.code == key {
                c.f(*entry);
                return;
            }

            Table::search_remainder(*entry, key, c)
        }
    }

    fn iter<'a>(&'a self) -> Items<'a> {
        Items { cur: None, items: self.items.iter() }
    }
}

impl<'a> Iterator<&'a Entry> for Items<'a> {
    fn next(&mut self) -> Option<&'a Entry> {
        let ret = match self.cur {
            None => {
                let i;
                loop {
                    match self.items.next() {
                        None => return None,
                        Some(&None) => {}
                        Some(&Some(ref a)) => { i = &**a; break }
                    }
                }
                self.cur = Some(&*i);
                &*i
            }
            Some(c) => c
        };
        match ret.next {
            None => { self.cur = None; }
            Some(ref next) => { self.cur = Some(&**next); }
        }
        return Some(ret);
    }
}

// Main program

fn pack_symbol(c: u8) -> u8 {
    match c as char {
        'a' | 'A' => 0,
        'c' | 'C' => 1,
        'g' | 'G' => 2,
        't' | 'T' => 3,
        _ => fail!("{}", c as char),
    }
}

fn unpack_symbol(c: u8) -> u8 {
    TABLE[c]
}

fn next_char<'a>(mut buf: &'a [u8]) -> &'a [u8] {
    loop {
        buf = buf.slice(1, buf.len());
        if buf.len() == 0 {
            break;
        }
        if buf[0] != (' ' as u8) && buf[0] != ('\t' as u8) &&
                buf[0] != ('\n' as u8) && buf[0] != 0 {
            break;
        }
    }
    buf
}

fn generate_frequencies(frequencies: &mut Table,
                        mut input: &[u8],
                        frame: i32) {
    let mut code = Code(0);

    // Pull first frame.
    for _ in range(0, frame) {
        code = code.push_char(input[0]);
        input = next_char(input);
    }
    frequencies.lookup(code, BumpCallback);

    while input.len() != 0 && input[0] != ('>' as u8) {
        code = code.rotate(input[0], frame);
        frequencies.lookup(code, BumpCallback);
        input = next_char(input);
    }
}

fn print_frequencies(frequencies: &Table, frame: i32) {
    let mut vector = Vec::new();
    for entry in frequencies.iter() {
        vector.push((entry.code, entry.count));
    }
    vector.as_mut_slice().sort();

    let mut total_count = 0;
    for &(_, count) in vector.iter() {
        total_count += count;
    }

    for &(key, count) in vector.iter() {
        println!("{} {:.3f}",
                 key.unpack(frame),
                 (count as f32 * 100.0) / (total_count as f32));
    }
}

fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
    frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
}

fn main() {
    let input = include_str!("shootout-k-nucleotide.data");
    let pos = input.find_str(">THREE").unwrap();
    let pos2 = pos + input.slice_from(pos).find_str("\n").unwrap();
    let input = input.slice_from(pos2 + 1).as_bytes();

    let mut frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 1);
    print_frequencies(&frequencies, 1);

    frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 2);
    print_frequencies(&frequencies, 2);

    for occurrence in OCCURRENCES.iter() {
        frequencies = Table::new();
        generate_frequencies(&mut frequencies,
                             input,
                             occurrence.len() as i32);
        print_occurrences(&mut frequencies, *occurrence);
    }
}
<commit_msg>auto merge of #13206 : TeXitoi/rust/fix-shootout-k-nucleotide, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android see #10393 #13206
// ignore-pretty

use std::ascii::OwnedStrAsciiExt;
use std::str;
use std::slice;

static TABLE: [u8, ..4] = [ 'A' as u8, 'C' as u8, 'G' as u8, 'T' as u8 ];
static TABLE_SIZE: uint = 2 << 16;

static OCCURRENCES: [&'static str, ..5] = [
    "GGT",
    "GGTA",
    "GGTATT",
    "GGTATTTTAATT",
    "GGTATTTTAATTTATAGT",
];

// Code implementation

#[deriving(Eq, Ord, TotalOrd, TotalEq)]
struct Code(u64);

impl Code {
    fn hash(&self) -> u64 {
        let Code(ret) = *self;
        return ret;
    }

    fn push_char(&self, c: u8) -> Code {
        Code((self.hash() << 2) + (pack_symbol(c) as u64))
    }

    fn rotate(&self, c: u8, frame: uint) -> Code {
        Code(self.push_char(c).hash() & ((1u64 << (2 * frame)) - 1))
    }

    fn pack(string: &str) -> Code {
        string.bytes().fold(Code(0u64), |a, b| a.push_char(b))
    }

    // FIXME: Inefficient.
    fn unpack(&self, frame: uint) -> ~str {
        let mut key = self.hash();
        let mut result = Vec::new();
        for _ in range(0, frame) {
            result.push(unpack_symbol((key as u8) & 3));
            key >>= 2;
        }

        result.reverse();
        str::from_utf8_owned(result.move_iter().collect()).unwrap()
    }
}

// Hash table implementation

trait TableCallback {
    fn f(&self, entry: &mut Entry);
}

struct BumpCallback;

impl TableCallback for BumpCallback {
    fn f(&self, entry: &mut Entry) {
        entry.count += 1;
    }
}

struct PrintCallback(&'static str);

impl TableCallback for PrintCallback {
    fn f(&self, entry: &mut Entry) {
        let PrintCallback(s) = *self;
        println!("{}\t{}", entry.count as int, s);
    }
}

struct Entry {
    code: Code,
    count: uint,
    next: Option<~Entry>,
}

struct Table {
    count: uint,
    items: Vec<Option<~Entry>> }

struct Items<'a> {
    cur: Option<&'a Entry>,
    items: slice::Items<'a, Option<~Entry>>,
}

impl Table {
    fn new() -> Table {
        Table {
            count: 0,
            items: Vec::from_fn(TABLE_SIZE, |_| None),
        }
    }

    fn search_remainder<C:TableCallback>(item: &mut Entry, key: Code, c: C) {
        match item.next {
            None => {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                item.next = Some(entry);
            }
            Some(ref mut entry) => {
                if entry.code == key {
                    c.f(*entry);
                    return;
                }

                Table::search_remainder(*entry, key, c)
            }
        }
    }

    fn lookup<C:TableCallback>(&mut self, key: Code, c: C) {
        let index = key.hash() % (TABLE_SIZE as u64);

        {
            if self.items.get(index as uint).is_none() {
                let mut entry = ~Entry {
                    code: key,
                    count: 0,
                    next: None,
                };
                c.f(entry);
                *self.items.get_mut(index as uint) = Some(entry);
                return;
            }
        }

        {
            let entry = &mut *self.items.get_mut(index as uint).get_mut_ref();
            if entry.code == key {
                c.f(*entry);
                return;
            }

            Table::search_remainder(*entry, key, c)
        }
    }

    fn iter<'a>(&'a self) -> Items<'a> {
        Items { cur: None, items: self.items.iter() }
    }
}

impl<'a> Iterator<&'a Entry> for Items<'a> {
    fn next(&mut self) -> Option<&'a Entry> {
        let ret = match self.cur {
            None => {
                let i;
                loop {
                    match self.items.next() {
                        None => return None,
                        Some(&None) => {}
                        Some(&Some(ref a)) => { i = &**a; break }
                    }
                }
                self.cur = Some(&*i);
                &*i
            }
            Some(c) => c
        };
        match ret.next {
            None => { self.cur = None; }
            Some(ref next) => { self.cur = Some(&**next); }
        }
        return Some(ret);
    }
}

// Main program

fn pack_symbol(c: u8) -> u8 {
    match c as char {
        'A' => 0,
        'C' => 1,
        'G' => 2,
        'T' => 3,
        _ => fail!("{}", c as char),
    }
}

fn unpack_symbol(c: u8) -> u8 {
    TABLE[c]
}

fn generate_frequencies(frequencies: &mut Table,
                        mut input: &[u8],
                        frame: uint) {
    if input.len() < frame { return; }
    let mut code = Code(0);

    // Pull first frame.
    for _ in range(0, frame) {
        code = code.push_char(input[0]);
        input = input.slice_from(1);
    }
    frequencies.lookup(code, BumpCallback);

    while input.len() != 0 && input[0] != ('>' as u8) {
        code = code.rotate(input[0], frame);
        frequencies.lookup(code, BumpCallback);
        input = input.slice_from(1);
    }
}

fn print_frequencies(frequencies: &Table, frame: uint) {
    let mut vector = Vec::new();
    for entry in frequencies.iter() {
        vector.push((entry.count, entry.code));
    }
    vector.as_mut_slice().sort();

    let mut total_count = 0;
    for &(count, _) in vector.iter() {
        total_count += count;
    }

    for &(count, key) in vector.iter().rev() {
        println!("{} {:.3f}",
                 key.unpack(frame),
                 (count as f32 * 100.0) / (total_count as f32));
    }
    println!("");
}

fn print_occurrences(frequencies: &mut Table, occurrence: &'static str) {
    frequencies.lookup(Code::pack(occurrence), PrintCallback(occurrence))
}

fn get_sequence<R: Buffer>(r: &mut R, key: &str) -> ~[u8] {
    let mut res = ~"";
    for l in r.lines().map(|l| l.ok().unwrap())
        .skip_while(|l| key != l.slice_to(key.len())).skip(1)
    {
        res.push_str(l.trim());
    }
    res.into_ascii_upper().into_bytes()
}

fn main() {
    let input = if std::os::getenv("RUST_BENCH").is_some() {
        let fd = std::io::File::open(&Path::new("shootout-k-nucleotide.data"));
        get_sequence(&mut std::io::BufferedReader::new(fd), ">THREE")
    } else {
        get_sequence(&mut std::io::stdin(), ">THREE")
    };

    let mut frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 1);
    print_frequencies(&frequencies, 1);

    frequencies = Table::new();
    generate_frequencies(&mut frequencies, input, 2);
    print_frequencies(&frequencies, 2);

    for occurrence in OCCURRENCES.iter() {
        frequencies = Table::new();
        generate_frequencies(&mut frequencies,
                             input,
                             occurrence.len());
        print_occurrences(&mut frequencies, *occurrence);
    }
}
<|endoftext|>


<commit_before>const ADD_A: u32 = 200u32.wrapping_add(55);
const ADD_B: u32 = 200u32.wrapping_add(u32::max_value());

const SUB_A: u32 = 100u32.wrapping_sub(100);
const SUB_B: u32 = 100u32.wrapping_sub(u32::max_value());

const MUL_A: u8 = 10u8.wrapping_mul(12);
const MUL_B: u8 = 25u8.wrapping_mul(12);

const SHL_A: u32 = 1u32.wrapping_shl(7);
const SHL_B: u32 = 1u32.wrapping_shl(128);

const SHR_A: u32 = 128u32.wrapping_shr(7);
const SHR_B: u32 = 128u32.wrapping_shr(128);

fn ident<T>(ident: T) -> T {
    ident
}

fn main() {
    assert_eq!(ADD_A, ident(255));
    assert_eq!(ADD_B, ident(199));

    assert_eq!(SUB_A, ident(0));
    assert_eq!(SUB_B, ident(101));

    assert_eq!(MUL_A, ident(120));
    assert_eq!(MUL_B, ident(44));

    assert_eq!(SHL_A, ident(128));
    assert_eq!(SHL_B, ident(1));

    assert_eq!(SHR_A, ident(1));
    assert_eq!(SHR_B, ident(128));
}
<commit_msg>const-int-wrapping.rs += wrapping_neg<commit_after>const ADD_A: u32 = 200u32.wrapping_add(55);
const ADD_B: u32 = 200u32.wrapping_add(u32::max_value());

const SUB_A: u32 = 100u32.wrapping_sub(100);
const SUB_B: u32 = 100u32.wrapping_sub(u32::max_value());

const MUL_A: u8 = 10u8.wrapping_mul(12);
const MUL_B: u8 = 25u8.wrapping_mul(12);

const SHL_A: u32 = 1u32.wrapping_shl(7);
const SHL_B: u32 = 1u32.wrapping_shl(128);

const SHR_A: u32 = 128u32.wrapping_shr(7);
const SHR_B: u32 = 128u32.wrapping_shr(128);

const NEG_A: u32 = 5u32.wrapping_neg();
const NEG_B: u32 = 1234567890u32.wrapping_neg();

fn ident<T>(ident: T) -> T {
    ident
}

fn main() {
    assert_eq!(ADD_A, ident(255));
    assert_eq!(ADD_B, ident(199));

    assert_eq!(SUB_A, ident(0));
    assert_eq!(SUB_B, ident(101));

    assert_eq!(MUL_A, ident(120));
    assert_eq!(MUL_B, ident(44));

    assert_eq!(SHL_A, ident(128));
    assert_eq!(SHL_B, ident(1));

    assert_eq!(SHR_A, ident(4294967291));
    assert_eq!(SHR_B, ident(3060399406));
}
<|endoftext|>


<commit_before>use std::slice;
use cose::decoder::decode_signature;
use cose::SignatureAlgorithm;

unsafe fn from_raw(ptr: *const u8, len: usize) -> Vec<u8> {
    slice::from_raw_parts(ptr, len).to_vec()
}

type VerifyCallback = extern "C" fn(*const u8, /* payload */
                                    usize, /* payload len */
                                    *const*const u8, /* cert_chain */
                                    usize, /* # certs */
                                    *const usize, /* cert lengths in cert_chain */
                                    *const u8, /* signer cert */
                                    usize, /* signer cert len */
                                    *const u8, /* signature bytes */
                                    usize, /* signature len */
                                    u8 /* signature algorithm */)
                                    -> bool;

#[no_mangle]
pub unsafe extern "C" fn verify_signature_with_cpp(
    payload: *const u8,
    payload_len: usize,
    cose_signature: *const u8,
    cose_signature_len: usize,
    verify_callback: VerifyCallback,
) -> bool {
    if payload.is_null() || cose_signature.is_null() || payload_len == 0 ||
        cose_signature_len == 0
    {
        return false;
    }

    // Build Rust variables from C parameters.
    let payload = from_raw(payload, payload_len);
    let cose_signature = from_raw(cose_signature, cose_signature_len);

    // Parse the incoming signature.
    let cose_signatures = decode_signature(cose_signature, &payload);
    let cose_signatures = match cose_signatures {
        Ok(signature) => signature,
        Err(_) => Vec::new(),
    };
    if cose_signatures.len() < 1 {
        return false;
    }

    let mut result = true;
    for cose_signature in cose_signatures {
        let signature_type = cose_signature.signature_type;
        // ES256 = 0, ES384 = 1, ES521 = 2, PS256 = 3
        let signature_type = match signature_type {
            SignatureAlgorithm::ES256 => 0,
            SignatureAlgorithm::ES384 => 1,
            SignatureAlgorithm::ES512 => 2,
            SignatureAlgorithm::PS256 => 3,
        };
        let signature_bytes = cose_signature.signature;
        let real_payload = cose_signature.to_verify;

        // Build cert chain params.
        let mut cert_lens:Vec<usize> = Vec::new();
        let mut certs:Vec<*const u8> = Vec::new();
        for cert in &cose_signature.certs {
            cert_lens.push(cert.len());
            certs.push(cert.as_ptr());
        }

        // Call callback to verify the parsed signatures.
        result &= verify_callback(
            real_payload.as_ptr(),
            real_payload.len(),
            certs.as_ptr(),
            cose_signature.certs.len(),
            cert_lens.as_ptr(),
            cose_signature.signer_cert.as_ptr(),
            cose_signature.signer_cert.len(),
            signature_bytes.as_ptr(),
            signature_bytes.len(),
            signature_type,
        );

        // We can stop early. The cose_signature is not valid.
        if !result {
            return result;
        }
    }

    result
}
<commit_msg>rustfmt<commit_after>use std::slice;
use cose::decoder::decode_signature;
use cose::SignatureAlgorithm;

unsafe fn from_raw(ptr: *const u8, len: usize) -> Vec<u8> {
    slice::from_raw_parts(ptr, len).to_vec()
}

type VerifyCallback = extern "C" fn(*const u8, /* payload */
                                    usize, /* payload len */
                                    *const *const u8, /* cert_chain */
                                    usize, /* # certs */
                                    *const usize, /* cert lengths in cert_chain */
                                    *const u8, /* signer cert */
                                    usize, /* signer cert len */
                                    *const u8, /* signature bytes */
                                    usize, /* signature len */
                                    u8 /* signature algorithm */)
                                    -> bool;

#[no_mangle]
pub unsafe extern "C" fn verify_signature_with_cpp(
    payload: *const u8,
    payload_len: usize,
    cose_signature: *const u8,
    cose_signature_len: usize,
    verify_callback: VerifyCallback,
) -> bool {
    if payload.is_null() || cose_signature.is_null() || payload_len == 0 ||
        cose_signature_len == 0
    {
        return false;
    }

    // Build Rust variables from C parameters.
    let payload = from_raw(payload, payload_len);
    let cose_signature = from_raw(cose_signature, cose_signature_len);

    // Parse the incoming signature.
    let cose_signatures = decode_signature(cose_signature, &payload);
    let cose_signatures = match cose_signatures {
        Ok(signature) => signature,
        Err(_) => Vec::new(),
    };
    if cose_signatures.len() < 1 {
        return false;
    }

    let mut result = true;
    for cose_signature in cose_signatures {
        let signature_type = cose_signature.signature_type;
        // ES256 = 0, ES384 = 1, ES521 = 2, PS256 = 3
        let signature_type = match signature_type {
            SignatureAlgorithm::ES256 => 0,
            SignatureAlgorithm::ES384 => 1,
            SignatureAlgorithm::ES512 => 2,
            SignatureAlgorithm::PS256 => 3,
        };
        let signature_bytes = cose_signature.signature;
        let real_payload = cose_signature.to_verify;

        // Build cert chain params.
        let mut cert_lens: Vec<usize> = Vec::new();
        let mut certs: Vec<*const u8> = Vec::new();
        for cert in &cose_signature.certs {
            cert_lens.push(cert.len());
            certs.push(cert.as_ptr());
        }

        // Call callback to verify the parsed signatures.
        result &= verify_callback(
            real_payload.as_ptr(),
            real_payload.len(),
            certs.as_ptr(),
            cose_signature.certs.len(),
            cert_lens.as_ptr(),
            cose_signature.signer_cert.as_ptr(),
            cose_signature.signer_cert.len(),
            signature_bytes.as_ptr(),
            signature_bytes.len(),
            signature_type,
        );

        // We can stop early. The cose_signature is not valid.
        if !result {
            return result;
        }
    }

    result
}
<|endoftext|>


<commit_before>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame<u16>>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context<u16>,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
        threads: 0,
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    if !cfg.is_null() {
        let _ = Box::from_raw(cfg);
    }
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    if !ctx.is_null() {
        let _ = Box::from_raw(ctx);
    }
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    if !frame.is_null() {
        let _ = Box::from_raw(frame);
    }
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
///
/// Returns:
/// - `0` on success,
/// - `> 0` if the input queue is full
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                EnoughData => 1,
                NeedMoreData | NeedMoreFrames => unreachable!(),
                _ => -1,
            }
        })
}

/// Receive encoded data
///
/// Returns:
/// - `0` on success
/// - `> 0` if additional frame data is required
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let packet = Packet {
                data: p.data.as_ptr(),
                len: p.data.len(),
                number: p.number,
                frame_type: p.frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                NeedMoreData |
                    NeedMoreFrames => 1,
                EnoughData => unreachable!(),
                _ => -1,
            }
        })
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    if !pkt.is_null() {
        let _ = Box::from_raw(pkt);
    }
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    if !sequence.is_null() {
        let _ = Box::from_raw(sequence);
    }
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<commit_msg>crav1e: Fix Packet providing a dangling pointer<commit_after>//! # C API for rav1e
//!
//! [rav1e](https://github.com/xiph/rav1e/) is an [AV1](https://aomediacodec.github.io/av1-spec/)
//! encoder written in [Rust](https://rust-lang.org)
//!
//! This is the C-compatible API

extern crate rav1e;
extern crate libc;

use std::slice;
use std::sync::Arc;

use std::ffi::CStr;
use std::os::raw::c_char;
use std::os::raw::c_int;

use libc::size_t;
use libc::ptrdiff_t;

/// Raw video Frame
///
/// It can be allocated throught rav1e_frame_new(), populated using rav1e_frame_fill_plane()
/// and freed using rav1e_frame_unref().
pub struct Frame(Arc<rav1e::Frame<u16>>);

type EncoderStatus=rav1e::EncoderStatus;

/// Encoder configuration
///
/// Instantiate it using rav1e_config_default() and fine-tune it using
/// rav1e_config_parse().
///
/// Use rav1e_config_unref() to free its memory.
pub struct Config {
    cfg: rav1e::Config,
    last_err: Option<EncoderStatus>,
}

/// Encoder context
///
/// Contains the encoding state, it is created by rav1e_context_new() using an
/// Encoder configuration.
///
/// Use rav1e_context_unref() to free its memory.
pub struct Context {
    ctx: rav1e::Context<u16>,
    last_err: Option<EncoderStatus>,
}

type FrameType = rav1e::FrameType;

/// Encoded Packet
///
/// The encoded packets are retrieved using rav1e_receive_packet().
///
/// Use rav1e_packet_unref() to free its memory.
#[repr(C)]
pub struct Packet {
    /// Encoded data buffer
    pub data: *const u8,
    /// Encoded data buffer size
    pub len: size_t,
    /// Frame sequence number
    pub number: u64,
    /// Frame type
    pub frame_type: FrameType,
}

type ChromaSamplePosition=rav1e::ChromaSamplePosition;
type ChromaSampling=rav1e::ChromaSampling;
type MatrixCoefficients=rav1e::MatrixCoefficients;
type ColorPrimaries=rav1e::ColorPrimaries;
type TransferCharacteristics=rav1e::TransferCharacteristics;
type Rational=rav1e::Rational;

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_default() -> *mut Config {
    let cfg = rav1e::Config {
        enc: rav1e::EncoderConfig::default(),
        threads: 0,
    };

    let c = Box::new(Config {
        cfg,
        last_err: None,
    });

    Box::into_raw(c)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_color_description(cfg: *mut Config,
                                                            matrix: MatrixCoefficients,
                                                            primaries: ColorPrimaries,
                                                            transfer: TransferCharacteristics)
{
    (*cfg).cfg.enc.color_description = Some(rav1e::ColorDescription {
        matrix_coefficients: matrix,
        color_primaries: primaries,
        transfer_characteristics: transfer,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_content_light(cfg: *mut Config,
                                                        max_content_light_level: u16,
                                                        max_frame_average_light_level: u16)
{
    (*cfg).cfg.enc.content_light = Some(rav1e::ContentLight {
        max_content_light_level,
        max_frame_average_light_level,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_set_mastering_display(cfg: *mut Config,
                                                            primaries: [rav1e::Point; 3],
                                                            white_point: rav1e::Point,
                                                            max_luminance: u32,
                                                            min_luminance: u32)
{
    (*cfg).cfg.enc.mastering_display = Some(rav1e::MasteringDisplay {
        primaries,
        white_point,
        max_luminance,
        min_luminance,
    });
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_config_unref(cfg: *mut Config) {
    if !cfg.is_null() {
        let _ = Box::from_raw(cfg);
    }
}

/// Set a configuration parameter using its key and value
///
/// Available keys and values
/// - "quantizer": 0-255, default 100
/// - "speed": 0-10, default 3
/// - "tune": "psnr"-"psychovisual", default "psnr"
///
/// Returns a negative value on non-zero.
#[no_mangle]
pub unsafe extern "C" fn rav1e_config_parse(
    cfg: *mut Config,
    key: *const c_char,
    value: *const c_char,
) -> c_int {
    let key = CStr::from_ptr(key).to_string_lossy();
    let value = CStr::from_ptr(value).to_string_lossy();

    (*cfg)
        .cfg
        .parse(&key, &value)
        .map(|_v| {
            (*cfg).last_err = None;
            0
        }).map_err(|e| (*cfg).last_err = Some(e))
        .unwrap_or(-1)
}

/// Generate a new encoding context from a populated encoder configuration
///
/// Multiple contexts can be generated through it.
#[no_mangle]
pub unsafe extern "C" fn rav1e_context_new(cfg: *const Config) -> *mut Context {
    let ctx = Context {
        ctx: (*cfg).cfg.new_context(),
        last_err: None,
    };

    Box::into_raw(Box::new(ctx))
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_context_unref(ctx: *mut Context) {
    if !ctx.is_null() {
        let _ = Box::from_raw(ctx);
    }
}

/// Produce a new frame from the encoding context
///
/// It must be populated using rav1e_frame_fill_plane().
///
/// The frame is reference counted and must be released passing it to rav1e_frame_unref(),
/// see rav1e_send_frame().
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_new(ctx: *const Context) -> *mut Frame {
    let f = (*ctx).ctx.new_frame();
    let frame = Box::new(Frame(f));

    Box::into_raw(frame)
}

#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_unref(frame: *mut Frame) {
    if !frame.is_null() {
        let _ = Box::from_raw(frame);
    }
}

/// Send the frame for encoding
///
/// The function increases the frame internal reference count and it can be passed multiple
/// times to different rav1e_send_frame().
///
/// Returns:
/// - `0` on success,
/// - `> 0` if the input queue is full
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_send_frame(ctx: *mut Context, frame: *const Frame) -> c_int {
    let frame = if frame.is_null() {
        None
    } else {
        Some((*frame).0.clone())
    };

    (*ctx)
        .ctx
        .send_frame(frame)
        .map(|_v| {
            (*ctx).last_err = None;
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                EnoughData => 1,
                NeedMoreData | NeedMoreFrames => unreachable!(),
                _ => -1,
            }
        })
}

/// Receive encoded data
///
/// Returns:
/// - `0` on success
/// - `> 0` if additional frame data is required
/// - `< 0` on unrecoverable failure
#[no_mangle]
pub unsafe extern "C" fn rav1e_receive_packet(
    ctx: *mut Context,
    pkt: *mut *mut Packet,
) -> c_int {
    (*ctx)
        .ctx
        .receive_packet()
        .map(|p| {
            (*ctx).last_err = None;
            let rav1e::Packet { data, number, frame_type, .. } = p;
            let len  = data.len();
            let data = Box::into_raw(data.into_boxed_slice()) as *const u8;
            let packet = Packet {
                data,
                len,
                number,
                frame_type,
            };
            *pkt = Box::into_raw(Box::new(packet));
            0
        }).unwrap_or_else(|e| {
            use rav1e::EncoderStatus::*;
            (*ctx).last_err = Some(e);
            match e {
                NeedMoreData |
                    NeedMoreFrames => 1,
                EnoughData => unreachable!(),
                _ => -1,
            }
        })
}

#[no_mangle]
pub unsafe extern fn rav1e_packet_unref(pkt: *mut Packet) {
    if !pkt.is_null() {
        let pkt = Box::from_raw(pkt);
        let _ = Box::from_raw(pkt.data as *mut u8);
    }
}

/// Produce a sequence header matching the current encoding context
///
/// Its format is compatible with the AV1 Matroska and ISOBMFF specification.
///
/// Use rav1e_container_sequence_header_unref() to free it.
#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header(ctx: *mut Context, buf_size: *mut size_t) -> *mut u8 {
    let buf = (*ctx).ctx.container_sequence_header();

    *buf_size = buf.len();
    Box::into_raw(buf.into_boxed_slice()) as *mut u8
}

#[no_mangle]
pub unsafe extern fn rav1e_container_sequence_header_unref(sequence: *mut u8) {
    if !sequence.is_null() {
        let _ = Box::from_raw(sequence);
    }
}

/// Fill a frame plane
///
/// Currently the frame contains 3 planes, the first is luminance followed by
/// chrominance.
///
/// The data is copied and this function has to be called for each plane.
///
/// frame: A frame provided by rav1e_frame_new()
/// plane: The index of the plane starting from 0
/// data: The data to be copied
/// data_len: Lenght of the buffer
/// stride: Plane line in bytes, including padding
/// bytewidth: Number of bytes per component, either 1 or 2
#[no_mangle]
pub unsafe extern "C" fn rav1e_frame_fill_plane(
    frame: *mut Frame,
    plane: c_int,
    data: *const u8,
    data_len: size_t,
    stride: ptrdiff_t,
    bytewidth: c_int,
) {
    let input = Arc::get_mut(&mut (*frame).0).unwrap();
    let data_slice = slice::from_raw_parts(data, data_len as usize);

    input.planes[plane as usize].copy_from_raw_u8(data_slice, stride as usize, bytewidth as usize);
}
<|endoftext|>


<commit_before>use api::{ Error, User };
use services::*;
use values::*;

use transformable_channels::mpsc::*;

use std::collections::HashMap;
use std::sync::Arc;

pub type ResultMap<K, T, E> = HashMap<K, Result<T, E>>;

/// A witness that we are currently watching for a value.
/// Watching stops when the guard is dropped.
pub trait AdapterWatchGuard : Send + Sync {
}

/// An API that adapter managers must implement
pub trait AdapterManagerHandle: Send {
    /// Add an adapter to the system.
    ///
    /// This version is optimized for Adapters that already implement Sync.
    ///
    /// # Errors
    ///
    /// Returns an error if an adapter with the same id is already present.
    fn add_adapter(& self, adapter: Arc<Adapter>) -> Result<(), Error>;

    /// Remove an adapter from the system, including all its services and channels.
    ///
    /// # Errors
    ///
    /// Returns an error if no adapter with this identifier exists. Otherwise, attempts
    /// to cleanup as much as possible, even if for some reason the system is in an
    /// inconsistent state.
    fn remove_adapter(& self, id: &Id<AdapterId>) -> Result<(), Error>;

    /// Add a service to the system. Called by the adapter when a new
    /// service (typically a new device) has been detected/configured.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if any of:
    /// - `service` has channels;
    /// - a service with id `service.id` is already installed on the system;
    /// - there is no adapter with id `service.lock`.
    fn add_service(& self, service: Service) -> Result<(), Error>;

    /// Remove a service previously registered on the system. Typically, called by
    /// an adapter when a service (e.g. a device) is disconnected.
    ///
    /// # Errors
    ///
    /// Returns an error if any of:
    /// - there is no such service;
    /// - there is an internal inconsistency, in which case this method will still attempt to
    /// cleanup before returning an error.
    fn remove_service(& self, service_id: &Id<ServiceId>) -> Result<(), Error>;

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose getters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_getter(& self, setter: Channel<Getter>) -> Result<(), Error>;

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its getters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_getter(& self, id: &Id<Getter>) -> Result<(), Error>;

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose setters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_setter(& self, setter: Channel<Setter>) -> Result<(), Error>;

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its setters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_setter(& self, id: &Id<Setter>) -> Result<(), Error>;
}

pub enum WatchEvent {
    /// Fired when we enter the range specified when we started watching, or if no range was
    /// specified, fired whenever a new value is available.
    Enter {
        id: Id<Getter>,
        value: Value
    },

    /// Fired when we exit the range specified when we started watching. If no range was
    /// specified, never fired.
    Exit {
        id: Id<Getter>,
        value: Value
    }
}

/// API that adapters must implement.
///
/// # Requirements
///
/// Channels and Services are expected to have a stable id, which persists between reboots
/// and { dis, re }connections.
///
/// Note that all methods are blocking. However, the underlying implementatino of adapters is
/// expected to either return quickly or be able to handle several requests concurrently.
pub trait Adapter: Send + Sync {
    /// An id unique to this adapter. This id must persist between
    /// reboots/reconnections.
    fn id(&self) -> Id<AdapterId>;

    /// The name of the adapter.
    fn name(&self) -> &str;
    fn vendor(&self) -> &str;
    fn version(&self) -> &[u32;4];
    // ... more metadata

    /// Request values from a group of channels.
    ///
    /// The AdapterManager always attempts to group calls to `fetch_values` by `Adapter`, and then
    /// expects the adapter to attempt to minimize the connections with the actual devices.
    ///
    /// The AdapterManager is in charge of keeping track of the age of values.
    fn fetch_values(&self, mut target: Vec<Id<Getter>>, _: User) -> ResultMap<Id<Getter>, Option<Value>, Error>;

    /// Request that values be sent to channels.
    ///
    /// The AdapterManager always attempts to group calls to `send_values` by `Adapter`, and then
    /// expects the adapter to attempt to minimize the connections with the actual devices.
    fn send_values(&self, values: HashMap<Id<Setter>, Value>, user: User) -> ResultMap<Id<Setter>, (), Error>;

    /// Watch a bunch of getters as they change.
    ///
    /// The `AdapterManager` always attempts to group calls to `fetch_values` by `Adapter`, and
    /// then expects the adapter to attempt to minimize the connections with the actual devices.
    /// The Adapter should however be ready to handle concurrent `register_watch` on the same
    /// devices, possibly with distinct `Option<Range>` options.
    ///
    /// If a `Range` option is set, the watcher expects to receive `EnterRange`/`ExitRange` events
    /// whenever the value available on the device enters/exits the range. If the `Range` is
    /// a `Range::Eq(x)`, the adapter may decide to reject the request or to interpret it as
    /// a `Range::BetweenEq { min: x, max: x }`.
    ///
    /// If no `Range` option is set, the watcher expects to receive `EnterRange` events whenever
    /// a new value is available on the device. The adapter may decide to reject the request if
    /// this is clearly not the expected usage for a device, or to throttle it.
    ///
    /// # Edge cases
    ///
    /// Note that the same `Id<Getter>` may appear several times. This is by design and adapters
    /// should handle this case, optimizing it if possible.
    ///
    /// Similarly, successive calls to `register_watch` may end up watching the same getter. The
    /// adapter should handle this case, optimizing it if possible.
    fn register_watch(&self, Vec<(Id<Getter>, Option<Range>, Box<ExtSender<WatchEvent>>)>) ->
            Vec<(Id<Getter>, Result<Box<AdapterWatchGuard>, Error>)>;

    /// Signal the adapter that it is time to stop.
    ///
    /// Ideally, the adapter should not return until all its threads have been stopped.
    fn stop(&self) {
        // By default, do nothing.
    }
}
<commit_msg>Simplifying the signature of register_watch<commit_after>use api::{ Error, User };
use services::*;
use values::*;

use transformable_channels::mpsc::*;

use std::collections::HashMap;
use std::sync::Arc;

pub type ResultMap<K, T, E> = HashMap<K, Result<T, E>>;

/// A witness that we are currently watching for a value.
/// Watching stops when the guard is dropped.
pub trait AdapterWatchGuard : Send + Sync {
}

/// An API that adapter managers must implement
pub trait AdapterManagerHandle: Send {
    /// Add an adapter to the system.
    ///
    /// This version is optimized for Adapters that already implement Sync.
    ///
    /// # Errors
    ///
    /// Returns an error if an adapter with the same id is already present.
    fn add_adapter(& self, adapter: Arc<Adapter>) -> Result<(), Error>;

    /// Remove an adapter from the system, including all its services and channels.
    ///
    /// # Errors
    ///
    /// Returns an error if no adapter with this identifier exists. Otherwise, attempts
    /// to cleanup as much as possible, even if for some reason the system is in an
    /// inconsistent state.
    fn remove_adapter(& self, id: &Id<AdapterId>) -> Result<(), Error>;

    /// Add a service to the system. Called by the adapter when a new
    /// service (typically a new device) has been detected/configured.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if any of:
    /// - `service` has channels;
    /// - a service with id `service.id` is already installed on the system;
    /// - there is no adapter with id `service.lock`.
    fn add_service(& self, service: Service) -> Result<(), Error>;

    /// Remove a service previously registered on the system. Typically, called by
    /// an adapter when a service (e.g. a device) is disconnected.
    ///
    /// # Errors
    ///
    /// Returns an error if any of:
    /// - there is no such service;
    /// - there is an internal inconsistency, in which case this method will still attempt to
    /// cleanup before returning an error.
    fn remove_service(& self, service_id: &Id<ServiceId>) -> Result<(), Error>;

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose getters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_getter(& self, setter: Channel<Getter>) -> Result<(), Error>;

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its getters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_getter(& self, id: &Id<Getter>) -> Result<(), Error>;

    /// Add a setter to the system. Typically, this is called by the adapter when a new
    /// service has been detected/configured. Some services may gain/lose setters at
    /// runtime depending on their configuration.
    ///
    /// # Requirements
    ///
    /// The adapter is in charge of making sure that identifiers persist across reboots.
    ///
    /// # Errors
    ///
    /// Returns an error if the adapter is not registered, the parent service is not
    /// registered, or a channel with the same identifier is already registered.
    /// In either cases, this method reverts all its changes.
    fn add_setter(& self, setter: Channel<Setter>) -> Result<(), Error>;

    /// Remove a setter previously registered on the system. Typically, called by
    /// an adapter when a service is reconfigured to remove one of its setters.
    ///
    /// # Error
    ///
    /// This method returns an error if the setter is not registered or if the service
    /// is not registered. In either case, it attemps to clean as much as possible, even
    /// if the state is inconsistent.
    fn remove_setter(& self, id: &Id<Setter>) -> Result<(), Error>;
}

pub enum WatchEvent {
    /// Fired when we enter the range specified when we started watching, or if no range was
    /// specified, fired whenever a new value is available.
    Enter {
        id: Id<Getter>,
        value: Value
    },

    /// Fired when we exit the range specified when we started watching. If no range was
    /// specified, never fired.
    Exit {
        id: Id<Getter>,
        value: Value
    }
}

/// API that adapters must implement.
///
/// # Requirements
///
/// Channels and Services are expected to have a stable id, which persists between reboots
/// and { dis, re }connections.
///
/// Note that all methods are blocking. However, the underlying implementatino of adapters is
/// expected to either return quickly or be able to handle several requests concurrently.
pub trait Adapter: Send + Sync {
    /// An id unique to this adapter. This id must persist between
    /// reboots/reconnections.
    fn id(&self) -> Id<AdapterId>;

    /// The name of the adapter.
    fn name(&self) -> &str;
    fn vendor(&self) -> &str;
    fn version(&self) -> &[u32;4];
    // ... more metadata

    /// Request values from a group of channels.
    ///
    /// The AdapterManager always attempts to group calls to `fetch_values` by `Adapter`, and then
    /// expects the adapter to attempt to minimize the connections with the actual devices.
    ///
    /// The AdapterManager is in charge of keeping track of the age of values.
    fn fetch_values(&self, mut target: Vec<Id<Getter>>, _: User) -> ResultMap<Id<Getter>, Option<Value>, Error>;

    /// Request that values be sent to channels.
    ///
    /// The AdapterManager always attempts to group calls to `send_values` by `Adapter`, and then
    /// expects the adapter to attempt to minimize the connections with the actual devices.
    fn send_values(&self, values: HashMap<Id<Setter>, Value>, user: User) -> ResultMap<Id<Setter>, (), Error>;

    /// Watch a bunch of getters as they change.
    ///
    /// The `AdapterManager` always attempts to group calls to `fetch_values` by `Adapter`, and
    /// then expects the adapter to attempt to minimize the connections with the actual devices.
    /// The Adapter should however be ready to handle concurrent `register_watch` on the same
    /// devices, possibly with distinct `Option<Range>` options.
    ///
    /// If a `Range` option is set, the watcher expects to receive `EnterRange`/`ExitRange` events
    /// whenever the value available on the device enters/exits the range. If the `Range` is
    /// a `Range::Eq(x)`, the adapter may decide to reject the request or to interpret it as
    /// a `Range::BetweenEq { min: x, max: x }`.
    ///
    /// If no `Range` option is set, the watcher expects to receive `EnterRange` events whenever
    /// a new value is available on the device. The adapter may decide to reject the request if
    /// this is clearly not the expected usage for a device, or to throttle it.
    ///
    /// # Edge cases
    ///
    /// Note that the same `Id<Getter>` may appear several times. This is by design and adapters
    /// should handle this case, optimizing it if possible.
    ///
    /// Similarly, successive calls to `register_watch` may end up watching the same getter. The
    /// adapter should handle this case, optimizing it if possible.
    fn register_watch(&self, Vec<WatchTarget>) ->
            WatchResult;

    /// Signal the adapter that it is time to stop.
    ///
    /// Ideally, the adapter should not return until all its threads have been stopped.
    fn stop(&self) {
        // By default, do nothing.
    }
}

pub type WatchTarget = (Id<Getter>, Option<Range>, Box<ExtSender<WatchEvent>>);
pub type WatchResult = Vec<(Id<Getter>, Result<Box<AdapterWatchGuard>, Error>)>;
<|endoftext|>