<commit_before>use std::path;
use std::process;

use rust_sodium;

use clap::{App, Arg, SubCommand, AppSettings};

use config;
use models;
use web;
use utils;

pub fn main() {
    let matches =
        App::new("mysteryshack")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Unterwaditzer & contributors")
        .about("A remoteStorage server.")
        .args_from_usage("-c, --config=[FILE] 'Use specified config file, defaults to ./config'")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("serve")
                    .about("Start server"))
        .subcommand(SubCommand::with_name("user")
                    .about("User management")
                    .setting(AppSettings::SubcommandRequired)
                    .arg(Arg::with_name("USERNAME")
                         .help("The username to perform the operation with.")
                         .required(true)
                         .index(1))
                    .subcommand(SubCommand::with_name("create")
                                .about("Create a new user"))
                    .subcommand(SubCommand::with_name("setpass")
                                .about("Change password for user"))
                    .subcommand(SubCommand::with_name("delete")
                                .about("Delete a user"))
                    .subcommand(SubCommand::with_name("authorize")
                                .about("Create a OAuth token. This is mostly useful for development.")
                                .arg(Arg::with_name("CLIENT_ID").required(true).index(1))
                                .arg(Arg::with_name("SCOPE").required(true).index(2))))
        .get_matches();

    assert!(rust_sodium::init());

    let config_path = path::Path::new(matches.value_of("config").unwrap_or("./config"));

    let config = match config::Config::read_file(config_path) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to parse config: {}", e);
            process::exit(1);
        }
    };

    clap_dispatch!(matches; {
        serve() => web::run_server(config),
        user(user_matches, USERNAME as username) => clap_dispatch!(user_matches; {
            create(_) => {
                let password_hash = models::PasswordHash::from_password(
                    utils::double_password_prompt("Password for new user: ").unwrap_or_else(|| process::exit(1)));

                match models::User::create(&config.data_path, username).map(|user| {
                    user.set_password_hash(password_hash)
                }) {
                    Ok(_) => (),
                    Err(e) => {
                        println!("Failed to create user {}: {}", username, e);
                        process::exit(1);
                    }
                };

                println!("Successfully created user {}", username);
            },
            setpass() => {
                let user = match models::User::get(&config.data_path, username) {
                    Some(x) => x,
                    None => {
                        println!("User does not exist: {}", username);
                        process::exit(1);
                    }
                };

                let password_hash = models::PasswordHash::from_password(
                    utils::double_password_prompt("New password: ").unwrap_or_else(|| process::exit(1)));
                match user.set_password_hash(password_hash) {
                    Ok(_) => (),
                    Err(e) => {
                        println!("Failed to set password for user {}: {}", username, e);
                        process::exit(1);
                    }
                };

                println!("Changed password for user {}", username);
            },
            delete() => {
                let user = match models::User::get(&config.data_path, username) {
                    Some(x) => x,
                    None => {
                        println!("User does not exist: {}", username);
                        process::exit(1);
                    }
                };

                println!("You are about to delete the user {} and ALL the user's user data. This
                         process is irreversible.", username);
                if !utils::prompt_confirm(format!("Do you want to delete the user {}?", username), false) {
                    println!("Aborted!");
                    process::exit(1);
                }

                match user.delete() {
                    Ok(_) => println!("Successfully deleted user {}.", username),
                    Err(e) => {
                        println!("Failed to delete user: {:?}", e);
                        process::exit(1);
                    }
                };
            },
            authorize(_, SCOPE as scope, CLIENT_ID as client_id) => {
                let user = match models::User::get(&config.data_path, username) {
                    Some(x) => x,
                    None => {
                        println!("User does not exist: {}", username);
                        process::exit(1);
                    }
                };

                let oauth_session = web::oauth::Session {
                    client_id: client_id.to_owned(),
                    permissions: match web::oauth::PermissionsMap::from_scope_string(scope) {
                        Some(x) => x,
                        None => {
                            println!("Invalid scope: {}", scope);
                            process::exit(1);
                        }
                    }
                };

                let (_, token) = models::Token::create(&user, oauth_session).unwrap();
                println!("{}", token.token(&user));
            }
        })
    });
}
<commit_msg>Move username arg<commit_after>use std::path;
use std::process;

use rust_sodium;

use clap::{App, Arg, SubCommand, AppSettings};

use config;
use models;
use web;
use utils;

pub fn main() {
    let username_arg = Arg::with_name("USERNAME")
        .help("The username to perform the operation with.")
        .required(true)
        .index(1);

    let matches =
        App::new("mysteryshack")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Markus Unterwaditzer & contributors")
        .about("A remoteStorage server.")
        .args_from_usage("-c, --config=[FILE] 'Use specified config file, defaults to ./config'")
        .setting(AppSettings::SubcommandRequired)
        .subcommand(SubCommand::with_name("serve")
                    .about("Start server"))
        .subcommand(SubCommand::with_name("user")
                    .about("User management")
                    .setting(AppSettings::SubcommandRequired)
                    .subcommand(SubCommand::with_name("create")
                                .about("Create a new user")
                                .arg(username_arg.clone()))
                    .subcommand(SubCommand::with_name("setpass")
                                .about("Change password for user")
                                .arg(username_arg.clone()))
                    .subcommand(SubCommand::with_name("delete")
                                .about("Delete a user")
                                .arg(username_arg.clone()))
                    .subcommand(SubCommand::with_name("authorize")
                                .about("Create a OAuth token. This is mostly useful for development.")
                                .arg(username_arg.clone())
                                .arg(Arg::with_name("CLIENT_ID").required(true).index(2))
                                .arg(Arg::with_name("SCOPE").required(true).index(3))))
        .get_matches();

    assert!(rust_sodium::init());

    let config_path = path::Path::new(matches.value_of("config").unwrap_or("./config"));

    let config = match config::Config::read_file(config_path) {
        Ok(x) => x,
        Err(e) => {
            println!("Failed to parse config: {}", e);
            process::exit(1);
        }
    };

    clap_dispatch!(matches; {
        serve() => web::run_server(config),
        user(user_matches) => clap_dispatch!(user_matches; {
            create(_, USERNAME as username) => {
                let password_hash = models::PasswordHash::from_password(
                    utils::double_password_prompt("Password for new user: ").unwrap_or_else(|| process::exit(1)));

                match models::User::create(&config.data_path, username).map(|user| {
                    user.set_password_hash(password_hash)
                }) {
                    Ok(_) => (),
                    Err(e) => {
                        println!("Failed to create user {}: {}", username, e);
                        process::exit(1);
                    }
                };

                println!("Successfully created user {}", username);
            },
            setpass(_, USERNAME as username) => {
                let user = match models::User::get(&config.data_path, username) {
                    Some(x) => x,
                    None => {
                        println!("User does not exist: {}", username);
                        process::exit(1);
                    }
                };

                let password_hash = models::PasswordHash::from_password(
                    utils::double_password_prompt("New password: ").unwrap_or_else(|| process::exit(1)));
                match user.set_password_hash(password_hash) {
                    Ok(_) => (),
                    Err(e) => {
                        println!("Failed to set password for user {}: {}", username, e);
                        process::exit(1);
                    }
                };

                println!("Changed password for user {}", username);
            },
            delete(_, USERNAME as username) => {
                let user = match models::User::get(&config.data_path, username) {
                    Some(x) => x,
                    None => {
                        println!("User does not exist: {}", username);
                        process::exit(1);
                    }
                };

                println!("You are about to delete the user {} and ALL the user's user data. This
                         process is irreversible.", username);
                if !utils::prompt_confirm(format!("Do you want to delete the user {}?", username), false) {
                    println!("Aborted!");
                    process::exit(1);
                }

                match user.delete() {
                    Ok(_) => println!("Successfully deleted user {}.", username),
                    Err(e) => {
                        println!("Failed to delete user: {:?}", e);
                        process::exit(1);
                    }
                };
            },
            authorize(_, USERNAME as username, SCOPE as scope, CLIENT_ID as client_id) => {
                let user = match models::User::get(&config.data_path, username) {
                    Some(x) => x,
                    None => {
                        println!("User does not exist: {}", username);
                        process::exit(1);
                    }
                };

                let oauth_session = web::oauth::Session {
                    client_id: client_id.to_owned(),
                    permissions: match web::oauth::PermissionsMap::from_scope_string(scope) {
                        Some(x) => x,
                        None => {
                            println!("Invalid scope: {}", scope);
                            process::exit(1);
                        }
                    }
                };

                let (_, token) = models::Token::create(&user, oauth_session).unwrap();
                println!("{}", token.token(&user));
            }
        })
    });
}
<|endoftext|>


<commit_before>use error::Error;
use ng::graph::{Dependency, Edge, Graph, Hierarchy, Module, Visibility, GLOB};

pub fn print(graph: &Graph, include_orphans: bool) -> Result<(), Error> {
    let indent_str: &str = "    ";
    let root_node: Module = find_root_module(&graph)?;

    println!(
        "digraph {{\n{}label=\"{}\";\npad=0.4;",
        indent_str,
        root_node.name()
    );

    println!("{}// Modules", indent_str);
    for module in graph.nodes().filter(|m| {
        // All modules if include_orhans is true,
        // else only non-orphaned modules.
        include_orphans || !m.is_orphan()
    }) {
        print!("{}", indent_str);
        print_node(module);
    }
    print!("\n");

    println!("{}// Hierarchy", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_hierarchy(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("{}// Dependencies", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_dependency(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("}}");
    Ok(())
}

fn find_root_module(graph: &Graph) -> Result<Module, Error> {
    let mut nodes = graph.nodes().filter(Module::is_root);
    match (nodes.next(), nodes.count()) {
        (None, _) => Err(Error::Graph("No root module found.".to_owned())),
        (Some(module), 0) => Ok(module),
        (Some(_), _) => Err(Error::Graph("There are multiple root modules.".to_owned())),
    }
}

fn format_dependency(from: Module, to: Module, edge: &Edge) -> Option<String> {
    if edge.dependency.is_empty() {
        None
    } else {
        match &edge.dependency {
            Dependency {
                refers_to_all,
                refers_to_mod,
                referred_members,
            } => {
                let color: &str = "azure3";
                // TODO: Set the overall font size manually as well, instead
                //       of relying on the default value.
                let font_size: u8 = 10;

                let mut label_parts: Vec<String> = Vec::new();
                if *refers_to_mod {
                    label_parts.push("self".to_owned());
                }
                if *refers_to_all {
                    label_parts.push(GLOB.to_owned());
                }
                let mut sorted_members = referred_members.iter().cloned().collect::<Vec<_>>();
                for member in sorted_members.drain(..) {
                    label_parts.push(member);
                }

                Some(format!(
                    "\"{}\" -> \"{}\" [weight=90, color={}, penwidth=2, label=<use {}>]",
                    from.path(),
                    to.path(),
                    color,
                    font_size,
                    color,
                    label_parts.join(", ")
                ))
            }
        }
    }
}

fn format_hierarchy(from: Module, to: Module, edge: &Edge) -> Option<String> {
    (match edge.hierarchy {
        Hierarchy::Child => Some("[weight=100, color=azure4, penwidth=3]"),
        Hierarchy::Orphan => Some("[weight=50, color=firebrick4, penwidth=1]"),
        Hierarchy::None => None,
    })
    .map(|edge_style| format!("\"{}\" -> \"{}\" {}", from.path(), to.path(), edge_style))
}

fn print_node(module: Module) {
    let (color, fillcolor): (&str, &str) = match module.visibility() {
        Some(Visibility::Public) => ("green4", "greenyellow"),
        Some(Visibility::Private) => ("darkgoldenrod", "khaki1"),
        None => ("firebrick4", "rosybrown1"), // Module is orphaned
    };
    println!(
        "\"{}\" [label=\"{}\", color={}, fontcolor={} style=filled, fillcolor={}]",
        module.path(),
        module.name(),
        color,
        color,
        fillcolor
    );
}
<commit_msg>Rename variable for consistency<commit_after>use error::Error;
use ng::graph::{Dependency, Edge, Graph, Hierarchy, Module, Visibility, GLOB};

pub fn print(graph: &Graph, include_orphans: bool) -> Result<(), Error> {
    let indent_str: &str = "    ";
    let root_node: Module = find_root_module(&graph)?;

    println!(
        "digraph {{\n{}label=\"{}\";\npad=0.4;",
        indent_str,
        root_node.name()
    );

    println!("{}// Modules", indent_str);
    for module in graph.nodes().filter(|m| {
        // All modules if include_orhans is true,
        // else only non-orphaned modules.
        include_orphans || !m.is_orphan()
    }) {
        print!("{}", indent_str);
        print_node(module);
    }
    print!("\n");

    println!("{}// Hierarchy", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_hierarchy(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("{}// Dependencies", indent_str);
    for (from, to, edge) in graph.all_edges() {
        format_dependency(from, to, edge).map(|s| println!("{}{}", indent_str, s));
    }
    print!("\n");

    println!("}}");
    Ok(())
}

fn find_root_module(graph: &Graph) -> Result<Module, Error> {
    let mut nodes = graph.nodes().filter(Module::is_root);
    match (nodes.next(), nodes.count()) {
        (None, _) => Err(Error::Graph("No root module found.".to_owned())),
        (Some(module), 0) => Ok(module),
        (Some(_), _) => Err(Error::Graph("There are multiple root modules.".to_owned())),
    }
}

fn format_dependency(from: Module, to: Module, edge: &Edge) -> Option<String> {
    if edge.dependency.is_empty() {
        None
    } else {
        match &edge.dependency {
            Dependency {
                refers_to_all,
                refers_to_mod,
                referred_members,
            } => {
                let color: &str = "azure3";
                // TODO: Set the overall font size manually as well, instead
                //       of relying on the default value.
                let font_size: u8 = 10;

                let mut label_parts: Vec<String> = Vec::new();
                if *refers_to_mod {
                    label_parts.push("self".to_owned());
                }
                if *refers_to_all {
                    label_parts.push(GLOB.to_owned());
                }
                let mut sorted_members = referred_members.iter().cloned().collect::<Vec<_>>();
                for member in sorted_members.drain(..) {
                    label_parts.push(member);
                }

                Some(format!(
                    "\"{}\" -> \"{}\" [weight=90, color={}, penwidth=2, label=<use {}>]",
                    from.path(),
                    to.path(),
                    color,
                    font_size,
                    color,
                    label_parts.join(", ")
                ))
            }
        }
    }
}

fn format_hierarchy(from: Module, to: Module, edge: &Edge) -> Option<String> {
    (match edge.hierarchy {
        Hierarchy::Child => Some("[weight=100, color=azure4, penwidth=3]"),
        Hierarchy::Orphan => Some("[weight=50, color=firebrick4, penwidth=1]"),
        Hierarchy::None => None,
    })
    .map(|edge_style| format!("\"{}\" -> \"{}\" {}", from.path(), to.path(), edge_style))
}

fn print_node(module: Module) {
    let (color, fill_color): (&str, &str) = match module.visibility() {
        Some(Visibility::Public) => ("green4", "greenyellow"),
        Some(Visibility::Private) => ("darkgoldenrod", "khaki1"),
        None => ("firebrick4", "rosybrown1"), // Module is orphaned
    };
    println!(
        "\"{}\" [label=\"{}\", color={}, fontcolor={} style=filled, fillcolor={}]",
        module.path(),
        module.name(),
        color,
        color,
        fill_color
    );
}
<|endoftext|>


<commit_before>use std::io::{TcpStream, BufferedReader, BufferedWriter};
use std::io::{IoResult};
use std::io::net::ip::{Ipv4Addr, Ipv6Addr};
use std::rc::{Rc, Weak};
//use std::sync::{Arc, Weak};
use std::cell::{RefCell};
use std::rand::{random};
use std::fmt::{Show, Formatter, FormatError};

use msg::{RawMessage, Message};
use cmd::{Command, REPLY, ResponseCode};

use server::{Event, ClientConnected, MessageReceived};

pub type SharedClient = Rc<RefCell<Client>>;
pub type WeaklySharedClient = Weak<RefCell<Client>>;

/// Unique client id
#[deriving(Hash)]
pub struct ClientId {
    id: [u64, ..2]
}

impl ClientId {
    /// The client id is losely inspired by SILC but the silc
    /// method of using the nickname is not applicable to IRC
    fn new(stream: &mut TcpStream) -> ClientId {
        ClientId {
            id: [
                match stream.socket_name().unwrap().ip {
                    Ipv4Addr(a, b, c, d) => a as u32 <<24 | b as u32<<16 | c as u32<<8 | d as u32,
                    Ipv6Addr(_, _, _, _, _, _, a, b) => a as u32 << 16 | b as u32
                } as u64 << 32
                | match stream.peer_name().unwrap().ip {
                    Ipv4Addr(a, b, c, d) => a as u32 <<24 | b as u32 <<16 | c as u32 <<8 | d as u32,
                    Ipv6Addr(_, _, _, _, _, _, a, b) => a as u32  << 16 | b as u32
                } as u64,
                random()
            ]
        }
    }
}

impl PartialEq for ClientId {
    #[inline]
    fn eq(&self, other: &ClientId) -> bool {
        self.id == other.id
    }
}

impl Eq for ClientId {}

impl Show for ClientId {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatError> {
        write!(fmt, "{:x}{:x}", self.id[0], self.id[1])
    }
}

impl Clone for ClientId {
    fn clone(&self) -> ClientId {
        ClientId { id: [ self.id[0], self.id[1] ] }
    }
}

/// Proxy that forwards a message to a client
#[deriving(Clone)]
pub struct ClientProxy {
    id: ClientId,
    nick: String,
    tx: Sender<RawMessage>
}

impl ClientProxy {
    fn new(id: ClientId, nick: String, tx: Sender<RawMessage>) -> ClientProxy {
        ClientProxy {
            id: id,
            nick: nick,
            tx: tx
        }
    }

    pub fn send_msg(&self, msg: RawMessage) {
        let _ = self.tx.send_opt(msg);
    }

    pub fn send_response<'a>(&'a self, command: ResponseCode,
                         params: &[&'a str], origin: &str) {
        let msg = RawMessage::new(
            REPLY(command),
            (vec![self.nick.as_slice()] + params).as_slice(),
            Some(origin)
        );
        let _ = self.tx.send_opt(msg);
    }
    pub fn id(&self) -> ClientId {
        self.id
    }
    pub fn update_nick(&mut self, nick: String) {
        self.nick = nick
    }
}

pub struct Client {
    id: ClientId,
    msg_tx: Sender<RawMessage>,
    stream: TcpStream,
    server_host: String,
    hostname: String,
    pub ip: String,
    pub nickname: String,
    pub username: String,
    pub realname: String,
}

impl Client {
    /// Spawns two threads for communication with the client
    /// Returns a SharedClient instance.
    /// TODO handle failures
    pub fn listen(host: String, mut stream: TcpStream,
                         tx: Sender<Event>) -> IoResult<()> {
        let (msg_tx, rx) = channel();
        let err_tx = msg_tx.clone();
        let peer_name = stream.peer_name().unwrap();
        let this = Client {
            id: ClientId::new(&mut stream),
            msg_tx: msg_tx,
            stream: stream.clone(),
            server_host: host,
            hostname: self::net::get_nameinfo(peer_name),
            ip: format!("{}", peer_name.ip),
            nickname: "".to_string(),
            username: "".to_string(),
            realname: "".to_string()
        };
        debug!("hostname of client is {}", this.hostname)
        let receiving_stream = stream.clone();
        let id = this.id;
        // this has to be sended first otherwise we have a nice race conditions
        tx.send(ClientConnected(this));
        spawn(proc() {
            // TODO: write a proper 510 char line iterator
            // as it is now it is probably very slow
            for line in BufferedReader::with_capacity(2, receiving_stream).lines() {
                match RawMessage::parse(line.unwrap().as_slice()
                .trim_right().as_bytes()) {
                    Ok(raw) => {
                        debug!("received message {}", raw.to_string());
                        match Message::from_raw_message(raw) {
                            Ok(message) => tx.send(MessageReceived(id, message)),
                            Err(err_msg) => {
                                // TODO inject proper receiver
                                err_tx.send(err_msg)
                            }
                        }
                    },
                    Err(_) => {}
                }
            }
        });
        spawn(proc() {
            // TODO: socket timeout
            // implement when pings are send out
            let mut output_stream = BufferedWriter::new(stream);
            for message in rx.iter() {
                debug!("sending message {}", message.to_string());
                output_stream.write(message.as_slice()).unwrap();
                output_stream.write(b"\r\n").unwrap();
                output_stream.flush().unwrap();
            }
        });
        Ok(())
    }

    /// Returns the mask
    pub fn real_mask(&self) -> String {
        format!("{}!{}@{}", self.nickname, self.username, self.hostname)
    }

    /// Converts the Client to a shared client
    pub fn as_shared(self) -> SharedClient {
        Rc::new(RefCell::new(self))
    }

    /// Sends a numeric response code to the client.
    /// Returns immediately.
    pub fn send_response<'a>(&'a self, response: ResponseCode,
                         origin: Option<&'a str>, reason: Option<&'a str>) {
        let mut params: Vec<&'a str> = Vec::with_capacity(2);
        if self.nickname.len() == 0 {
            // TODO follow rust-dev
            // this static lifetime made all lifetime annotations necessary
            params.push("*")
        } else {
            params.push(self.nickname.as_slice())
        }
        if origin.is_some() {
            params.push(origin.unwrap())
        }
        if reason.is_some() {
            params.push(reason.unwrap())
        }
        self.send_msg(RawMessage::new(REPLY(response),
            params.as_slice(), Some(self.server_host.as_slice())))
    }

    /// Sends constructs a message and sends it the client
    pub fn send(&self, command: Command, params: &[&str], prefix: Option<&str>) {
        // Note mem::transmute is safe in this case, since &[&str] is just &[&[u8].
        self.send_msg(RawMessage::new(
            command, params, prefix
        ))
    }

    /// Sends a message to the client.
    /// Returns immediately.
    pub fn send_msg(&self, message: RawMessage) {
        let _ = self.msg_tx.send(message);
    }

    /// Closes the connection to the client
    pub fn close_connection(&mut self) {
        let _ = self.stream.close_read();
        let _ = self.stream.close_write();
    }

    /// Accessor for the client id
    #[inline]
    pub fn id(&self) -> ClientId {
        self.id
    }

    /// Returns a proxy to the current client
    pub fn proxy(&self) -> ClientProxy {
        ClientProxy::new(self.id(), self.nickname.clone(), self.msg_tx.clone())
    }
}

impl PartialEq for Client {
    #[inline]
    fn eq(&self, other: &Client) -> bool {
        self.id == other.id
    }
}

impl Eq for Client {}

mod net {

    use std::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
    use libc::{malloc, sockaddr, sockaddr_in, sockaddr_in6, in_addr, in6_addr, c_int, c_char, socklen_t, AF_INET, AF_INET6};
    use std::mem::{size_of, transmute};
    use std::string;

    /*
     const char *
         inet_ntop(int af, const void * restrict src, char * restrict dst,
             socklen_t size);
    */
    extern {
        fn getnameinfo(sa: *const sockaddr, salen: socklen_t,
                       host: *mut c_char, hostlen: socklen_t,
                       serv: *mut c_char, servlen: socklen_t,
                       flags: c_int) -> c_int;
    }

    //static NI_NUMERICHOST: c_int = 0x00000002;
    //static NI_NAMEREQD: c_int = 0x00000004;

    /// Returns the hostname for an ip address
    /// TODO: make this safe, see manpage
    pub fn get_nameinfo(peer_socket: SocketAddr) -> String {
        let SocketAddr { ip: ip, port: port } = peer_socket;
        let buf: *mut i8;
        let _ = unsafe {
            let hostlen = 80;
            buf = transmute(malloc(hostlen as u64 + 1));
            match ip {
                Ipv4Addr(a, b, c, d) => {
                    let addr = in_addr {
                        s_addr: a as u32 << 24
                              | b as u32 << 16
                              | c as u32 << 8
                              | d as u32
                    };
                    let sockaddr = sockaddr_in {
                        sin_len: size_of::<sockaddr_in>() as u8,
                        sin_family: AF_INET as u8,
                        sin_port: port,
                        sin_addr: addr,
                        sin_zero: [0, ..8]
                    };
                    getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in>() as i32,
                                buf, hostlen, transmute(0u), 0, 0)
                },
                Ipv6Addr(a, b, c, d, e, f, g, h) => {
                    let sockaddr = sockaddr_in6 {
                        sin6_len: size_of::<sockaddr_in6>() as u8,
                        sin6_family: AF_INET6 as u8,
                        sin6_port: port,
                        sin6_flowinfo: 0,
                        sin6_addr: in6_addr {
                            s6_addr: [a, b, c, d, e, f, g, h]
                        },
                        sin6_scope_id: 0,
                    };
                    getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in6>() as i32,
                                buf, hostlen, transmute(0u), 0, 0)
                },
            }

        };
        unsafe {string::raw::from_buf(transmute(buf))}

    }
}<commit_msg>changed buffering<commit_after>use std::io::{TcpStream, BufferedReader, BufferedWriter};
use std::io::{IoResult};
use std::io::net::ip::{Ipv4Addr, Ipv6Addr};
use std::rc::{Rc, Weak};
//use std::sync::{Arc, Weak};
use std::cell::{RefCell};
use std::rand::{random};
use std::fmt::{Show, Formatter, FormatError};

use msg::{RawMessage, Message};
use cmd::{Command, REPLY, ResponseCode};

use server::{Event, ClientConnected, MessageReceived};

pub type SharedClient = Rc<RefCell<Client>>;
pub type WeaklySharedClient = Weak<RefCell<Client>>;

/// Unique client id
#[deriving(Hash)]
pub struct ClientId {
    id: [u64, ..2]
}

impl ClientId {
    /// The client id is losely inspired by SILC but the silc
    /// method of using the nickname is not applicable to IRC
    fn new(stream: &mut TcpStream) -> ClientId {
        ClientId {
            id: [
                match stream.socket_name().unwrap().ip {
                    Ipv4Addr(a, b, c, d) => a as u32 <<24 | b as u32<<16 | c as u32<<8 | d as u32,
                    Ipv6Addr(_, _, _, _, _, _, a, b) => a as u32 << 16 | b as u32
                } as u64 << 32
                | match stream.peer_name().unwrap().ip {
                    Ipv4Addr(a, b, c, d) => a as u32 <<24 | b as u32 <<16 | c as u32 <<8 | d as u32,
                    Ipv6Addr(_, _, _, _, _, _, a, b) => a as u32  << 16 | b as u32
                } as u64,
                random()
            ]
        }
    }
}

impl PartialEq for ClientId {
    #[inline]
    fn eq(&self, other: &ClientId) -> bool {
        self.id == other.id
    }
}

impl Eq for ClientId {}

impl Show for ClientId {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatError> {
        write!(fmt, "{:x}{:x}", self.id[0], self.id[1])
    }
}

impl Clone for ClientId {
    fn clone(&self) -> ClientId {
        ClientId { id: [ self.id[0], self.id[1] ] }
    }
}

/// Proxy that forwards a message to a client
#[deriving(Clone)]
pub struct ClientProxy {
    id: ClientId,
    nick: String,
    tx: Sender<RawMessage>
}

impl ClientProxy {
    fn new(id: ClientId, nick: String, tx: Sender<RawMessage>) -> ClientProxy {
        ClientProxy {
            id: id,
            nick: nick,
            tx: tx
        }
    }

    pub fn send_msg(&self, msg: RawMessage) {
        let _ = self.tx.send_opt(msg);
    }

    pub fn send_response<'a>(&'a self, command: ResponseCode,
                         params: &[&'a str], origin: &str) {
        let msg = RawMessage::new(
            REPLY(command),
            (vec![self.nick.as_slice()] + params).as_slice(),
            Some(origin)
        );
        let _ = self.tx.send_opt(msg);
    }
    pub fn id(&self) -> ClientId {
        self.id
    }
    pub fn update_nick(&mut self, nick: String) {
        self.nick = nick
    }
}

pub struct Client {
    id: ClientId,
    msg_tx: Sender<RawMessage>,
    stream: TcpStream,
    server_host: String,
    hostname: String,
    pub ip: String,
    pub nickname: String,
    pub username: String,
    pub realname: String,
}

impl Client {
    /// Spawns two threads for communication with the client
    /// Returns a SharedClient instance.
    /// TODO handle failures
    pub fn listen(host: String, mut stream: TcpStream,
                         tx: Sender<Event>) -> IoResult<()> {
        let (msg_tx, rx) = channel();
        let err_tx = msg_tx.clone();
        let peer_name = stream.peer_name().unwrap();
        let this = Client {
            id: ClientId::new(&mut stream),
            msg_tx: msg_tx,
            stream: stream.clone(),
            server_host: host,
            hostname: self::net::get_nameinfo(peer_name),
            ip: format!("{}", peer_name.ip),
            nickname: "".to_string(),
            username: "".to_string(),
            realname: "".to_string()
        };
        debug!("hostname of client is {}", this.hostname)
        let receiving_stream = stream.clone();
        let id = this.id;
        // this has to be sended first otherwise we have a nice race conditions
        tx.send(ClientConnected(this));
        spawn(proc() {
            // TODO: write a proper 510 char line iterator
            // as it is now it is probably very slow
            // TODO handle failures properly
            for line in BufferedReader::new(receiving_stream).lines() {
                match RawMessage::parse(line.unwrap().as_slice()
                .trim_right().as_bytes()) {
                    Ok(raw) => {
                        debug!("received message {}", raw.to_string());
                        match Message::from_raw_message(raw) {
                            Ok(message) => tx.send(MessageReceived(id, message)),
                            Err(err_msg) => {
                                // TODO inject proper receiver
                                err_tx.send(err_msg)
                            }
                        }
                    },
                    Err(_) => {}
                }
            }
        });
        spawn(proc() {
            // TODO: socket timeout
            // implement when pings are send out
            // TODO handle failures properly
            let mut output_stream = BufferedWriter::new(stream);
            for message in rx.iter() {
                debug!("sending message {}", message.to_string());
                output_stream.write(message.as_slice()).unwrap();
                output_stream.write(b"\r\n").unwrap();
                output_stream.flush().unwrap();
            }
        });
        Ok(())
    }

    /// Returns the mask
    pub fn real_mask(&self) -> String {
        format!("{}!{}@{}", self.nickname, self.username, self.hostname)
    }

    /// Converts the Client to a shared client
    pub fn as_shared(self) -> SharedClient {
        Rc::new(RefCell::new(self))
    }

    /// Sends a numeric response code to the client.
    /// Returns immediately.
    pub fn send_response<'a>(&'a self, response: ResponseCode,
                         origin: Option<&'a str>, reason: Option<&'a str>) {
        let mut params: Vec<&'a str> = Vec::with_capacity(2);
        if self.nickname.len() == 0 {
            // TODO follow rust-dev
            // this static lifetime made all lifetime annotations necessary
            params.push("*")
        } else {
            params.push(self.nickname.as_slice())
        }
        if origin.is_some() {
            params.push(origin.unwrap())
        }
        if reason.is_some() {
            params.push(reason.unwrap())
        }
        self.send_msg(RawMessage::new(REPLY(response),
            params.as_slice(), Some(self.server_host.as_slice())))
    }

    /// Sends constructs a message and sends it the client
    pub fn send(&self, command: Command, params: &[&str], prefix: Option<&str>) {
        // Note mem::transmute is safe in this case, since &[&str] is just &[&[u8].
        self.send_msg(RawMessage::new(
            command, params, prefix
        ))
    }

    /// Sends a message to the client.
    /// Returns immediately.
    pub fn send_msg(&self, message: RawMessage) {
        let _ = self.msg_tx.send(message);
    }

    /// Closes the connection to the client
    pub fn close_connection(&mut self) {
        let _ = self.stream.close_read();
        let _ = self.stream.close_write();
    }

    /// Accessor for the client id
    #[inline]
    pub fn id(&self) -> ClientId {
        self.id
    }

    /// Returns a proxy to the current client
    pub fn proxy(&self) -> ClientProxy {
        ClientProxy::new(self.id(), self.nickname.clone(), self.msg_tx.clone())
    }
}

impl PartialEq for Client {
    #[inline]
    fn eq(&self, other: &Client) -> bool {
        self.id == other.id
    }
}

impl Eq for Client {}

mod net {

    use std::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
    use libc::{malloc, sockaddr, sockaddr_in, sockaddr_in6, in_addr, in6_addr, c_int, c_char, socklen_t, AF_INET, AF_INET6};
    use std::mem::{size_of, transmute};
    use std::string;

    /*
     const char *
         inet_ntop(int af, const void * restrict src, char * restrict dst,
             socklen_t size);
    */
    extern {
        fn getnameinfo(sa: *const sockaddr, salen: socklen_t,
                       host: *mut c_char, hostlen: socklen_t,
                       serv: *mut c_char, servlen: socklen_t,
                       flags: c_int) -> c_int;
    }

    //static NI_NUMERICHOST: c_int = 0x00000002;
    //static NI_NAMEREQD: c_int = 0x00000004;

    /// Returns the hostname for an ip address
    /// TODO: make this safe, see manpage
    pub fn get_nameinfo(peer_socket: SocketAddr) -> String {
        let SocketAddr { ip: ip, port: port } = peer_socket;
        let buf: *mut i8;
        let _ = unsafe {
            let hostlen = 80;
            buf = transmute(malloc(hostlen as u64 + 1));
            match ip {
                Ipv4Addr(a, b, c, d) => {
                    let addr = in_addr {
                        s_addr: a as u32 << 24
                              | b as u32 << 16
                              | c as u32 << 8
                              | d as u32
                    };
                    let sockaddr = sockaddr_in {
                        sin_len: size_of::<sockaddr_in>() as u8,
                        sin_family: AF_INET as u8,
                        sin_port: port,
                        sin_addr: addr,
                        sin_zero: [0, ..8]
                    };
                    getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in>() as i32,
                                buf, hostlen, transmute(0u), 0, 0)
                },
                Ipv6Addr(a, b, c, d, e, f, g, h) => {
                    let sockaddr = sockaddr_in6 {
                        sin6_len: size_of::<sockaddr_in6>() as u8,
                        sin6_family: AF_INET6 as u8,
                        sin6_port: port,
                        sin6_flowinfo: 0,
                        sin6_addr: in6_addr {
                            s6_addr: [a, b, c, d, e, f, g, h]
                        },
                        sin6_scope_id: 0,
                    };
                    getnameinfo(transmute(&sockaddr), size_of::<sockaddr_in6>() as i32,
                                buf, hostlen, transmute(0u), 0, 0)
                },
            }

        };
        unsafe {string::raw::from_buf(transmute(buf))}

    }
}<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fleetspeak_proto::common::{Message, Address};
use fleetspeak_proto::channel::{StartupData};
use lazy_static::lazy_static;
use prost;
use prost_types;
use std::io::{Read, Write, Result};
use std::marker::{Send, Sync};
use std::sync::Mutex;

pub struct Connection<R, W> {
    pub input: R,
    pub output: W,
}

impl<R: Read, W: Write> Connection<R, W> {

    pub fn new(input: R, output: W) -> Result<Self> {
        let mut conn = Connection {
            input: input,
            output: output,
        };
        conn.handshake()?;

        Ok(conn)
    }

    pub fn heartbeat(&mut self) -> Result<()> {
        let msg = Message {
            message_type: String::from("Heartbeat"),
            destination: Some(Address {
                service_name: String::from("system"),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn startup(&mut self, version: &str) -> Result<()> {
        let data = StartupData {
            pid: std::process::id() as i64,
            version: String::from(version),
        };

        let mut buf = Vec::new();
        prost::Message::encode(&data, &mut buf).map_err(invalid_data_error)?;

        let msg = Message {
            message_type: String::from("StartupData"),
            destination: Some(Address {
                service_name: String::from("system"),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: buf,
                type_url: String::from("type.googleapis.com/fleetspeak.channel.StartupData"),
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn send<M>(&mut self, service: &str, kind: &str, data: M) -> Result<()>
    where
        M: prost::Message,
    {
        let mut buf = Vec::new();
        prost::Message::encode(&data, &mut buf).map_err(invalid_data_error)?;

        let msg = Message {
            message_type: String::from(kind),
            destination: Some(Address {
                service_name: String::from(service),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: buf.to_vec(),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn receive<M>(&mut self) -> Result<M>
    where
        M: prost::Message + Default,
    {
        let msg = self.collect()?;

        // It is not clear what is the best approach here. If there is no data,
        // should we error-out or return a default value? For the time being we
        // stick to the default approach, but if this proves to be not working
        // well in practice, it might be reconsidered.
        let data = match msg.data {
            Some(data) => data,
            None => return Ok(Default::default()),
        };

        prost::Message::decode(&data.value[..]).map_err(invalid_data_error)
    }

    fn emit(&mut self, msg: Message) -> Result<()> {
        let mut buf = Vec::new();
        prost::Message::encode(&msg, &mut buf).map_err(invalid_data_error)?;

        self.output.write_u32::<LittleEndian>(buf.len() as u32)?;
        self.output.write(&buf)?;
        self.write_magic()?;
        self.output.flush()?;

        Ok(())
    }

    fn collect(&mut self) -> Result<Message> {
        let len = self.input.read_u32::<LittleEndian>()? as usize;
        let mut buf = vec!(0; len);
        self.input.read_exact(&mut buf[..])?;
        self.read_magic()?;

        prost::Message::decode(&buf[..]).map_err(invalid_data_error)
    }

    fn handshake(&mut self) -> Result<()> {
        self.write_magic()?;
        self.output.flush()?;
        self.read_magic()?;

        Ok(())
    }

    fn write_magic(&mut self) -> Result<()> {
        self.output.write_u32::<LittleEndian>(MAGIC)?;

        Ok(())
    }

    fn read_magic(&mut self) -> Result<()> {
        let magic = self.input.read_u32::<LittleEndian>()?;
        if magic != MAGIC {
            let err = invalid_data_error(format!("invalid magic `{}`", magic));
            return Err(err);
        }

        Ok(())
    }
}

fn invalid_data_error<E>(err: E) -> std::io::Error
where
    E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
    return std::io::Error::new(std::io::ErrorKind::InvalidData, err);
}

const MAGIC: u32 = 0xf1ee1001;

fn open(var: &str) -> std::fs::File {
    let fd = match std::env::var(var) {
        Ok(fd) => fd,
        Err(err) => panic!("invalid variable `{}`: {}", var, err),
    };

    let fd = match fd.parse() {
        Ok(fd) => fd,
        Err(err) => panic!("failed to parse a file descriptor: {}", err),
    };

    // TODO: Add support for Windows.
    unsafe {
        std::os::unix::io::FromRawFd::from_raw_fd(fd)
    }
}

lazy_static! {
    static ref CONNECTION: Mutex<Connection<std::fs::File, std::fs::File>> = {
        let input = open("FLEETSPEAK_COMMS_CHANNEL_INFD");
        let output = open("FLEETSPEAK_COMMS_CHANNEL_OUTFD");

        let conn = Connection::new(input, output).expect("handshake failure");
        Mutex::new(conn)
    };
}

pub fn heartbeat() -> Result<()> {
    connected(|conn| conn.heartbeat())
}

pub fn startup(version: &str) -> Result<()> {
    connected(|conn| conn.startup(version))
}

pub fn send<M>(service: &str, kind: &str, data: M) -> Result<()>
where
    M: prost::Message,
{
    connected(|conn| conn.send(service, kind, data))
}

pub fn receive<M>() -> Result<M>
where
    M: prost::Message + Default,
{
    connected(|conn| conn.receive())
}

fn connected<F, T>(f: F) -> Result<T>
where
    F: FnOnce(&mut Connection<std::fs::File, std::fs::File>) -> Result<T>
{
    let mut conn = CONNECTION.lock().expect("poisoned connection mutex");
    f(&mut conn)
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use super::*;

    #[test]
    fn handshake_good_magic() {
        let mut buf_in = [0; 1024];
        let mut buf_out = [0; 1024];

        let mut cur = Cursor::new(&mut buf_in[..]);
        assert!(cur.write_u32::<LittleEndian>(MAGIC).is_ok());

        let cur_in = Cursor::new(&mut buf_in[..]);
        let cur_out = Cursor::new(&mut buf_out[..]);
        assert!(Connection::new(cur_in, cur_out).is_ok());

        let mut cur = Cursor::new(&mut buf_out[..]);
        assert_eq!(cur.read_u32::<LittleEndian>().unwrap(), MAGIC);
    }

    #[test]
    fn handshake_bad_magic() {
        let mut buf_in = [0; 1024];
        let mut buf_out = [0; 1024];

        let mut cur = Cursor::new(&mut buf_in[..]);
        assert!(cur.write_u32::<LittleEndian>(0xf1ee1337).is_ok());

        let cur_in = Cursor::new(&mut buf_in[..]);
        let cur_out = Cursor::new(&mut buf_out[..]);
        assert!(Connection::new(cur_in, cur_out).is_err());
    }
}
<commit_msg>Avoid unnecessary vector allocation.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fleetspeak_proto::common::{Message, Address};
use fleetspeak_proto::channel::{StartupData};
use lazy_static::lazy_static;
use prost;
use prost_types;
use std::io::{Read, Write, Result};
use std::marker::{Send, Sync};
use std::sync::Mutex;

pub struct Connection<R, W> {
    pub input: R,
    pub output: W,
}

impl<R: Read, W: Write> Connection<R, W> {

    pub fn new(input: R, output: W) -> Result<Self> {
        let mut conn = Connection {
            input: input,
            output: output,
        };
        conn.handshake()?;

        Ok(conn)
    }

    pub fn heartbeat(&mut self) -> Result<()> {
        let msg = Message {
            message_type: String::from("Heartbeat"),
            destination: Some(Address {
                service_name: String::from("system"),
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn startup(&mut self, version: &str) -> Result<()> {
        let data = StartupData {
            pid: std::process::id() as i64,
            version: String::from(version),
        };

        let mut buf = Vec::new();
        prost::Message::encode(&data, &mut buf).map_err(invalid_data_error)?;

        let msg = Message {
            message_type: String::from("StartupData"),
            destination: Some(Address {
                service_name: String::from("system"),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: buf,
                type_url: String::from("type.googleapis.com/fleetspeak.channel.StartupData"),
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn send<M>(&mut self, service: &str, kind: &str, data: M) -> Result<()>
    where
        M: prost::Message,
    {
        let mut buf = Vec::new();
        prost::Message::encode(&data, &mut buf).map_err(invalid_data_error)?;

        let msg = Message {
            message_type: String::from(kind),
            destination: Some(Address {
                service_name: String::from(service),
                ..Default::default()
            }),
            data: Some(prost_types::Any {
                value: buf,
                ..Default::default()
            }),
            ..Default::default()
        };

        self.emit(msg)
    }

    pub fn receive<M>(&mut self) -> Result<M>
    where
        M: prost::Message + Default,
    {
        let msg = self.collect()?;

        // It is not clear what is the best approach here. If there is no data,
        // should we error-out or return a default value? For the time being we
        // stick to the default approach, but if this proves to be not working
        // well in practice, it might be reconsidered.
        let data = match msg.data {
            Some(data) => data,
            None => return Ok(Default::default()),
        };

        prost::Message::decode(&data.value[..]).map_err(invalid_data_error)
    }

    fn emit(&mut self, msg: Message) -> Result<()> {
        let mut buf = Vec::new();
        prost::Message::encode(&msg, &mut buf).map_err(invalid_data_error)?;

        self.output.write_u32::<LittleEndian>(buf.len() as u32)?;
        self.output.write(&buf)?;
        self.write_magic()?;
        self.output.flush()?;

        Ok(())
    }

    fn collect(&mut self) -> Result<Message> {
        let len = self.input.read_u32::<LittleEndian>()? as usize;
        let mut buf = vec!(0; len);
        self.input.read_exact(&mut buf[..])?;
        self.read_magic()?;

        prost::Message::decode(&buf[..]).map_err(invalid_data_error)
    }

    fn handshake(&mut self) -> Result<()> {
        self.write_magic()?;
        self.output.flush()?;
        self.read_magic()?;

        Ok(())
    }

    fn write_magic(&mut self) -> Result<()> {
        self.output.write_u32::<LittleEndian>(MAGIC)?;

        Ok(())
    }

    fn read_magic(&mut self) -> Result<()> {
        let magic = self.input.read_u32::<LittleEndian>()?;
        if magic != MAGIC {
            let err = invalid_data_error(format!("invalid magic `{}`", magic));
            return Err(err);
        }

        Ok(())
    }
}

fn invalid_data_error<E>(err: E) -> std::io::Error
where
    E: Into<Box<dyn std::error::Error + Send + Sync>>,
{
    return std::io::Error::new(std::io::ErrorKind::InvalidData, err);
}

const MAGIC: u32 = 0xf1ee1001;

fn open(var: &str) -> std::fs::File {
    let fd = match std::env::var(var) {
        Ok(fd) => fd,
        Err(err) => panic!("invalid variable `{}`: {}", var, err),
    };

    let fd = match fd.parse() {
        Ok(fd) => fd,
        Err(err) => panic!("failed to parse a file descriptor: {}", err),
    };

    // TODO: Add support for Windows.
    unsafe {
        std::os::unix::io::FromRawFd::from_raw_fd(fd)
    }
}

lazy_static! {
    static ref CONNECTION: Mutex<Connection<std::fs::File, std::fs::File>> = {
        let input = open("FLEETSPEAK_COMMS_CHANNEL_INFD");
        let output = open("FLEETSPEAK_COMMS_CHANNEL_OUTFD");

        let conn = Connection::new(input, output).expect("handshake failure");
        Mutex::new(conn)
    };
}

pub fn heartbeat() -> Result<()> {
    connected(|conn| conn.heartbeat())
}

pub fn startup(version: &str) -> Result<()> {
    connected(|conn| conn.startup(version))
}

pub fn send<M>(service: &str, kind: &str, data: M) -> Result<()>
where
    M: prost::Message,
{
    connected(|conn| conn.send(service, kind, data))
}

pub fn receive<M>() -> Result<M>
where
    M: prost::Message + Default,
{
    connected(|conn| conn.receive())
}

fn connected<F, T>(f: F) -> Result<T>
where
    F: FnOnce(&mut Connection<std::fs::File, std::fs::File>) -> Result<T>
{
    let mut conn = CONNECTION.lock().expect("poisoned connection mutex");
    f(&mut conn)
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use super::*;

    #[test]
    fn handshake_good_magic() {
        let mut buf_in = [0; 1024];
        let mut buf_out = [0; 1024];

        let mut cur = Cursor::new(&mut buf_in[..]);
        assert!(cur.write_u32::<LittleEndian>(MAGIC).is_ok());

        let cur_in = Cursor::new(&mut buf_in[..]);
        let cur_out = Cursor::new(&mut buf_out[..]);
        assert!(Connection::new(cur_in, cur_out).is_ok());

        let mut cur = Cursor::new(&mut buf_out[..]);
        assert_eq!(cur.read_u32::<LittleEndian>().unwrap(), MAGIC);
    }

    #[test]
    fn handshake_bad_magic() {
        let mut buf_in = [0; 1024];
        let mut buf_out = [0; 1024];

        let mut cur = Cursor::new(&mut buf_in[..]);
        assert!(cur.write_u32::<LittleEndian>(0xf1ee1337).is_ok());

        let cur_in = Cursor::new(&mut buf_in[..]);
        let cur_out = Cursor::new(&mut buf_out[..]);
        assert!(Connection::new(cur_in, cur_out).is_err());
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::io;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{Future, Sink, Stream};
use futures::sync::{mpsc, oneshot};

use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_io::AsyncRead;

use super::resp;

/// TODO: comeback and optimise this number
const DEFAULT_BUFFER_SIZE:usize = 100;

/// Connect to a Redis server and return paired Sink and Stream for reading and writing
/// asynchronously.
fn connect(addr: &SocketAddr, core: &Core) -> Box<Future<Item=ClientConnection, Error=io::Error>> {
    let handle = core.handle();
    let client_con = TcpStream::connect(addr, &handle).map(move |socket| {
        let framed = socket.framed(resp::RespCodec);
        let (write_f, read_f) = framed.split();
        let write_b = write_f.buffer(DEFAULT_BUFFER_SIZE);
        ClientConnection {
            sender: ClientSink(Box::new(write_b)),
            receiver: ClientStream(Box::new(read_f))
        }
    });
    Box::new(client_con)
}

/// TODO - is the boxing necessary?  It makes the type signature much simpler
struct ClientSink(Box<Sink<SinkItem=resp::RespValue, SinkError=io::Error>>);
struct ClientStream(Box<Stream<Item=resp::RespValue, Error=io::Error>>);

/// A low-level client connection representing a sender and a receiver.
///
/// The two halves operate independently from one another
struct ClientConnection {
    sender: ClientSink,
    receiver: ClientStream
}

fn paired_connect(addr: &SocketAddr, core: &Core) -> Box<Future<Item=PairedConnection, Error=io::Error>> {
    let handle = core.handle();
    let paired_con = connect(addr, core).map(move |connection| {
        let ClientConnection { sender, receiver } = connection;
        let (out_tx, out_rx) = mpsc::unbounded();
        let sender = out_rx.fold(sender.0, |sender, msg| {
            sender.send(msg).map_err(|_| ())
        });
        let resp_queue:Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>> = Arc::new(Mutex::new(VecDeque::new()));
        let receiver_queue = resp_queue.clone();
        let receiver = receiver.0.for_each(move |msg| {
            let mut queue = receiver_queue.lock().expect("Untainted lock");
            let dest = queue.pop_front().expect("Not empty queue");
            dest.send(msg).expect("Successful send");
            Ok(())
        });
        handle.spawn(sender.map(|_| ()));
        handle.spawn(receiver.map_err(|_| ()));
        PairedConnection {
            out_tx: out_tx,
            resp_queue: resp_queue
        }
    });
    Box::new(paired_con)
}

struct PairedConnection {
    out_tx: mpsc::UnboundedSender<resp::RespValue>,
    resp_queue: Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>>
}

impl PairedConnection {
    fn send(&self, msg: resp::RespValue) -> Box<Future<Item=resp::RespValue, Error=()>> {
        let (tx, rx) = oneshot::channel();
        let mut queue = self.resp_queue.lock().expect("Untainted queue");
        queue.push_back(tx);
        mpsc::UnboundedSender::send(&self.out_tx, msg).expect("Successful send");
        Box::new(rx.map_err(|_| ()))
    }
}

#[cfg(test)]
mod test {
    use std::io;

    use futures::{Future, Sink, Stream};
    use futures::stream;

    use tokio_core::reactor::Core;

    use super::resp;

    #[test]
    fn can_connect() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connection = super::connect(&addr, &core).and_then(|connection| {
            let a = connection.sender.0.send(["PING", "TEST"].as_ref().into());
            let b = connection.receiver.0.take(1).collect();
            a.join(b)
        });
        let (_, values) = core.run(connection).unwrap();
        assert_eq!(values.len(), 1);
        assert_eq!(values[0], "TEST".into());
    }

    #[test]
    fn complex_test() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();
        let connection = super::connect(&addr, &core).and_then(|connection| {
            let mut ops = Vec::<resp::RespValue>::new();
            ops.push(["FLUSH"].as_ref().into());
            ops.extend((0..1000).map(|i| ["SADD", "test_set", &format!("VALUE: {}", i)].as_ref().into()));
            ops.push(["SMEMBERS", "test_set"].as_ref().into());
            let ops_r:Vec<Result<resp::RespValue, io::Error>> = ops.into_iter().map(Result::Ok).collect();
            let send = connection.sender.0.send_all(stream::iter(ops_r));
            let receive = connection.receiver.0.skip(1001).take(1).collect();
            send.join(receive)
        });
        let (_, values) = core.run(connection).unwrap();
        assert_eq!(values.len(), 1);
        let values = match &values[0] {
            &resp::RespValue::Array(ref values) => values.clone(),
            _ => panic!("Not an array")
        };
        assert_eq!(values.len(), 1000);
    }

    #[test]
    fn can_paired_connect() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr, &core).and_then(|connection| {
            let res_f = connection.send(["PING", "TEST"].as_ref().into());
            connection.send(["GET", "X"].as_ref().into());
            connection.send(["SET", "X", "123"].as_ref().into());
            // TODO - map_err only neccessary to ensure the chain of errors makes sense,
            // should instead define a higher-level error type and propagate those
            // instead
            res_f.map_err(|_| io::Error::new(io::ErrorKind::Other, "unexpected"))
        });
        let result = core.run(connect_f).unwrap();
        assert_eq!(result, "TEST".into());
    }
}<commit_msg>Added failing test to be investigated<commit_after>use std::collections::VecDeque;
use std::io;
use std::net::SocketAddr;
use std::sync::{Arc, Mutex};

use futures::{Future, Sink, Stream};
use futures::sync::{mpsc, oneshot};

use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_io::AsyncRead;

use super::resp;

/// TODO: comeback and optimise this number
const DEFAULT_BUFFER_SIZE:usize = 100;

/// Connect to a Redis server and return paired Sink and Stream for reading and writing
/// asynchronously.
fn connect(addr: &SocketAddr, core: &Core) -> Box<Future<Item=ClientConnection, Error=io::Error>> {
    let handle = core.handle();
    let client_con = TcpStream::connect(addr, &handle).map(move |socket| {
        let framed = socket.framed(resp::RespCodec);
        let (write_f, read_f) = framed.split();
        let write_b = write_f.buffer(DEFAULT_BUFFER_SIZE);
        ClientConnection {
            sender: ClientSink(Box::new(write_b)),
            receiver: ClientStream(Box::new(read_f))
        }
    });
    Box::new(client_con)
}

/// TODO - is the boxing necessary?  It makes the type signature much simpler
struct ClientSink(Box<Sink<SinkItem=resp::RespValue, SinkError=io::Error>>);
struct ClientStream(Box<Stream<Item=resp::RespValue, Error=io::Error>>);

/// A low-level client connection representing a sender and a receiver.
///
/// The two halves operate independently from one another
struct ClientConnection {
    sender: ClientSink,
    receiver: ClientStream
}

fn paired_connect(addr: &SocketAddr, core: &Core) -> Box<Future<Item=PairedConnection, Error=io::Error>> {
    let handle = core.handle();
    let paired_con = connect(addr, core).map(move |connection| {
        let ClientConnection { sender, receiver } = connection;
        let (out_tx, out_rx) = mpsc::unbounded();
        let sender = out_rx.fold(sender.0, |sender, msg| {
            sender.send(msg).map_err(|_| ())
        });
        let resp_queue:Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>> = Arc::new(Mutex::new(VecDeque::new()));
        let receiver_queue = resp_queue.clone();
        let receiver = receiver.0.for_each(move |msg| {
            let mut queue = receiver_queue.lock().expect("Untainted lock");
            let dest = queue.pop_front().expect("Not empty queue");
            dest.send(msg).expect("Successful send");
            Ok(())
        });
        handle.spawn(sender.map(|_| ()));
        handle.spawn(receiver.map_err(|_| ()));
        PairedConnection {
            out_tx: out_tx,
            resp_queue: resp_queue
        }
    });
    Box::new(paired_con)
}

struct PairedConnection {
    out_tx: mpsc::UnboundedSender<resp::RespValue>,
    resp_queue: Arc<Mutex<VecDeque<oneshot::Sender<resp::RespValue>>>>
}

impl PairedConnection {
    fn send(&self, msg: resp::RespValue) -> Box<Future<Item=resp::RespValue, Error=()>> {
        let (tx, rx) = oneshot::channel();
        let mut queue = self.resp_queue.lock().expect("Untainted queue");
        queue.push_back(tx);
        mpsc::UnboundedSender::send(&self.out_tx, msg).expect("Successful send");
        Box::new(rx.map_err(|_| ()))
    }
}

#[cfg(test)]
mod test {
    use std::io;
    use std::sync::Arc;

    use futures::{Future, Sink, Stream};
    use futures::stream;

    use tokio_core::reactor::Core;

    use super::resp;

    #[test]
    fn can_connect() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connection = super::connect(&addr, &core).and_then(|connection| {
            let a = connection.sender.0.send(["PING", "TEST"].as_ref().into());
            let b = connection.receiver.0.take(1).collect();
            a.join(b)
        });
        let (_, values) = core.run(connection).unwrap();
        assert_eq!(values.len(), 1);
        assert_eq!(values[0], "TEST".into());
    }

    #[test]
    fn complex_test() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();
        let connection = super::connect(&addr, &core).and_then(|connection| {
            let mut ops = Vec::<resp::RespValue>::new();
            ops.push(["FLUSH"].as_ref().into());
            ops.extend((0..1000).map(|i| ["SADD", "test_set", &format!("VALUE: {}", i)].as_ref().into()));
            ops.push(["SMEMBERS", "test_set"].as_ref().into());
            let ops_r:Vec<Result<resp::RespValue, io::Error>> = ops.into_iter().map(Result::Ok).collect();
            let send = connection.sender.0.send_all(stream::iter(ops_r));
            let receive = connection.receiver.0.skip(1001).take(1).collect();
            send.join(receive)
        });
        let (_, values) = core.run(connection).unwrap();
        assert_eq!(values.len(), 1);
        let values = match &values[0] {
            &resp::RespValue::Array(ref values) => values.clone(),
            _ => panic!("Not an array")
        };
        assert_eq!(values.len(), 1000);
    }

    #[test]
    fn can_paired_connect() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr, &core).and_then(|connection| {
            let res_f = connection.send(["PING", "TEST"].as_ref().into());
            connection.send(["GET", "X"].as_ref().into());
            connection.send(["SET", "X", "123"].as_ref().into());
            // TODO - map_err only neccessary to ensure the chain of errors makes sense,
            // should instead define a higher-level error type and propagate those
            // instead
            res_f.map_err(|_| io::Error::new(io::ErrorKind::Other, "unexpected"))
        });
        let result = core.run(connect_f).unwrap();
        assert_eq!(result, "TEST".into());
    }

    #[test]
    fn complex_paired_connect() {
        let mut core = Core::new().unwrap();
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr, &core).and_then(|connection| {
            let connection = Arc::new(connection);
            let inner_connection = connection.clone();
            connection.send(["INCR", "CTR"].as_ref().into()).and_then(move |value| {
                inner_connection.send(resp::RespValue::Array(vec!["SET".into(), "LASTCTR".into(), value]))
            }).map_err(|_| io::Error::new(io::ErrorKind::Other, "unexpected"))
        });
        let result = core.run(connect_f).unwrap();
        assert_eq!(result, resp::RespValue::SimpleString("OK".into()));
    }
}<|endoftext|>


<commit_before>use hyper::client::Client;
use hyper::client::response::Response;
use hyper::error::Error;
use hyper::header::Headers;
use hyper::method::Method;

/// Trait that represents some methods to send a specific request
pub trait GetResponse {
    /// Given a specific URL, get the response from the target server
    fn get_http_response(url: &str) -> Result<Response, Error>;
    /// Given a specific URL and an header, get the response from the target server
    fn get_http_response_using_headers(url: &str, header: Headers) -> Result<Response, Error>;
}

impl GetResponse for Client {
    fn get_http_response(url: &str) -> Result<Response, Error> {
        Client::new().request(Method::Get, url).send()
    }
    fn get_http_response_using_headers(url: &str,
                                       custom_header: Headers)
                                       -> Result<Response, Error> {
        Client::new().request(Method::Get, url).headers(custom_header).send()
    }
}<commit_msg>A trait to get easily HTTP responses, using a HTTP header<commit_after>use hyper::client::Client;
use hyper::client::response::Response;
use hyper::error::Error;
use hyper::header::Headers;
use hyper::method::Method;

/// Trait that represents some methods to send a specific request
pub trait GetResponse {
    /// Given a specific URL, get the response from the target server
    fn get_http_response(&self, url: &str) -> Result<Response, Error>;
    /// Given a specific URL and an header, get the response from the target server
    fn get_http_response_using_headers(&self,
                                       url: &str,
                                       header: Headers)
                                       -> Result<Response, Error>;
}

impl GetResponse for Client {
    fn get_http_response(&self, url: &str) -> Result<Response, Error> {
        self.request(Method::Get, url).send()
    }
    fn get_http_response_using_headers(&self,
                                       url: &str,
                                       custom_header: Headers)
                                       -> Result<Response, Error> {
        self.request(Method::Get, url).headers(custom_header).send()
    }
}<|endoftext|>


<commit_before>extern crate libc;

use std::io;
use std::io::fs;
use std::io::File;
use std::path::Path;
use std::collections::HashMap;

use document::Document;

pub struct Runner;

impl Runner {
    pub fn run(path_string: &str) {
        let base_path      = Path::new(path_string);
        let documents_path = base_path.join("_posts");
        let layout_path    = base_path.join("_layouts");
        let index_path     = base_path.join("index.tpl");
        let build_path     = base_path.join("build");

        println!("Generating site in {}\n", path_string);

        let index     = Runner::parse_document(&index_path);
        let posts     = Runner::parse_documents(&documents_path);
        let post_path = Runner::create_dirs(&build_path);

        Runner::create_files(&build_path, &post_path, &layout_path, index, posts);
    }

    fn parse_documents(path: &Path) -> Vec<Document> {

        let paths = fs::readdir(path);
        let mut documents = vec!();

        if paths.is_ok() {
            for path in paths.unwrap().iter() {
                if path.extension_str().unwrap() != "tpl" {
                    continue;
                }

                documents.push(Runner::parse_document(path));
            }
        } else {
            println!("Path {} doesn't exist\n", path.display());
            unsafe { libc::exit(1 as libc::c_int); }
        }

        return documents;
    }

    fn parse_document(path: &Path) -> Document {
        let attributes = Runner::extract_attributes(path);
        let content    = Runner::extract_content(path);

        Document::new(
            attributes,
            content,
            path.filestem_str().unwrap().to_string() + ".html",
        )
    }

    fn parse_file(path: &Path) -> String {
        match File::open(path) {
            // TODO handle IOResult
            Ok(mut x) => x.read_to_string().unwrap(),
            Err(e) => {
                println!("File {} doesn't exist\n", path.display());
                // TODO panic!
                fail!();
            }
        }
    }

    fn create_dirs(build_path: &Path) -> Path {
        let postpath = build_path.join("posts");

        fs::mkdir(build_path, io::USER_RWX);
        fs::mkdir(&postpath, io::USER_RWX);

        // TODO: copy non cobalt relevant folders into /build folder (assets, stylesheets, etc...)

        println!("Directory {} created\n", build_path.display());

        return postpath;
    }

    fn create_files(index_path: &Path, document_path: &Path, layout_path: &Path, index: Document, documents: Vec<Document>) {
        index.create_file(index_path, layout_path);

        for document in documents.iter() {
            document.create_file(document_path, layout_path);
        }
    }

    fn extract_attributes(path: &Path) -> HashMap<String, String> {
        let mut attributes = HashMap::new();
        attributes.insert("name".to_string(), path.filestem_str().unwrap().to_string());

        let content = Runner::parse_file(path);

        if content.as_slice().contains("---") {
            let mut content_splits = content.as_slice().split_str("---");

            let attribute_string = content_splits.nth(0u).unwrap();

            for attribute_line in attribute_string.split_str("\n") {
                if !attribute_line.contains_char(':') {
                    continue;
                }

                let mut attribute_split = attribute_line.split(':');

                // TODO: Refactor, find a better way for doing this
                // .nth() method is consuming the iterator and therefore the 0th index on the second method
                // is in real index 1
                let key   = attribute_split.nth(0u).unwrap().trim_chars(' ').to_string().clone();
                let value = attribute_split.nth(0u).unwrap().trim_chars(' ').to_string().clone();

                attributes.insert(key, value);
            }
        }

        return attributes;
    }

    fn extract_content(path: &Path) -> String {
        let content = Runner::parse_file(path);

        if content.as_slice().contains("---") {
            let mut content_splits = content.as_slice().split_str("---");

            return content_splits.nth(1u).unwrap().to_string();
        }

        return content;
    }
}
<commit_msg>fail safer<commit_after>extern crate libc;

use std::io;
use std::io::fs;
use std::io::File;
use std::path::Path;
use std::collections::HashMap;

use document::Document;

pub struct Runner;

impl Runner {
    pub fn run(path_string: &str) {
        let base_path      = Path::new(path_string);
        let documents_path = base_path.join("_posts");
        let layout_path    = base_path.join("_layouts");
        let index_path     = base_path.join("index.tpl");
        let build_path     = base_path.join("build");

        println!("Generating site in {}\n", path_string);

        let index     = Runner::parse_document(&index_path);
        let posts     = Runner::parse_documents(&documents_path);
        let post_path = Runner::create_dirs(&build_path);

        Runner::create_files(&build_path, &post_path, &layout_path, index, posts);
    }

    fn parse_documents(path: &Path) -> Vec<Document> {

        let paths = fs::readdir(path);
        let mut documents = vec!();

        if paths.is_ok() {
            for path in paths.unwrap().iter() {
                if path.extension_str().unwrap() != "tpl" {
                    continue;
                }

                documents.push(Runner::parse_document(path));
            }
        } else {
            // TODO panic!
            fail!("Path {} doesn't exist\n", path.display());
        }

        return documents;
    }

    fn parse_document(path: &Path) -> Document {
        let attributes = Runner::extract_attributes(path);
        let content    = Runner::extract_content(path);

        Document::new(
            attributes,
            content,
            path.filestem_str().unwrap().to_string() + ".html",
        )
    }

    fn parse_file(path: &Path) -> String {
        match File::open(path) {
            // TODO handle IOResult
            Ok(mut x) => x.read_to_string().unwrap(),
            // TODO panic!
            Err(e) => fail!("File {} doesn't exist\n", path.display())
        }
    }

    fn create_dirs(build_path: &Path) -> Path {
        let postpath = build_path.join("posts");

        fs::mkdir(build_path, io::USER_RWX);
        fs::mkdir(&postpath, io::USER_RWX);

        // TODO: copy non cobalt relevant folders into /build folder (assets, stylesheets, etc...)

        println!("Directory {} created\n", build_path.display());

        return postpath;
    }

    fn create_files(index_path: &Path, document_path: &Path, layout_path: &Path, index: Document, documents: Vec<Document>) {
        index.create_file(index_path, layout_path);

        for document in documents.iter() {
            document.create_file(document_path, layout_path);
        }
    }

    fn extract_attributes(path: &Path) -> HashMap<String, String> {
        let mut attributes = HashMap::new();
        attributes.insert("name".to_string(), path.filestem_str().unwrap().to_string());

        let content = Runner::parse_file(path);

        if content.as_slice().contains("---") {
            let mut content_splits = content.as_slice().split_str("---");

            let attribute_string = content_splits.nth(0u).unwrap();

            for attribute_line in attribute_string.split_str("\n") {
                if !attribute_line.contains_char(':') {
                    continue;
                }

                let mut attribute_split = attribute_line.split(':');

                // TODO: Refactor, find a better way for doing this
                // .nth() method is consuming the iterator and therefore the 0th index on the second method
                // is in real index 1
                let key   = attribute_split.nth(0u).unwrap().trim_chars(' ').to_string().clone();
                let value = attribute_split.nth(0u).unwrap().trim_chars(' ').to_string().clone();

                attributes.insert(key, value);
            }
        }

        return attributes;
    }

    fn extract_content(path: &Path) -> String {
        let content = Runner::parse_file(path);

        if content.as_slice().contains("---") {
            let mut content_splits = content.as_slice().split_str("---");

            return content_splits.nth(1u).unwrap().to_string();
        }

        return content;
    }
}
<|endoftext|>


<commit_before>pub struct SceneNode {
    pub name: String,
    pub material_index: usize,
    pub start_position: i32,
    pub end_position: i32,
}

#[derive(Debug)]
#[derive(Clone)]
pub struct Material {
    pub name: String,
    pub diffuse: [f32; 3],
    pub diffuse_texname: String,
}

#[derive(Debug)]
pub struct Shader {
    pub name: String,
    // pub vertex_source_110: String,
    // pub fragment_source_110: String,
    // pub vertex_source_120: String,
    // pub fragment_source_120: String,
    // pub vertex_source_130: String,
    // pub fragment_source_130: String,
    pub vertex_source_140: String,
    pub fragment_source_140: String, /* pub vertex_source_150: String,
                                      * pub fragment_source_150: String,
                                      * pub vertex_source_330: String,
                                      * pub fragment_source_330: String,
                                      * pub vertex_source_400: String,
                                      * pub fragment_source_400: String,
                                      * pub vertex_source_410: String,
                                      * pub fragment_source_401: String,
                                      * pub vertex_source_420: String,
                                      * pub fragment_source_420: String,
                                      * pub vertex_source_430: String,
                                      * pub fragment_source_430: String,
                                      * pub vertex_source_100es: String,
                                      * pub fragment_source_100es: String,
                                      * pub vertex_source_300es: String,
                                      * pub fragment_source_300es: String,
                                      * */
}

#[derive(Copy, Clone)]
pub struct Vertex8f32 {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub texcoord: [f32; 2],
}

#[derive(Clone)]
pub struct Mesh {
    pub name: String,
    pub vertices: Vec<Vertex8f32>,
    pub material_index: usize,
}

pub struct ImageBlob {
    pub name: String,
    pub image: Vec<u8>,
}

pub struct Scene {
    pub materials: Vec<Material>,
    pub meshes: Vec<Mesh>,
    pub shaders: Vec<Shader>,
    pub images: Vec<ImageBlob>,
}
<commit_msg>made Shader struct no longer version specific, and removed shader from Scene struct.<commit_after>pub struct SceneNode {
    pub name: String,
    pub material_index: usize,
    pub start_position: i32,
    pub end_position: i32,
}

#[derive(Debug)]
#[derive(Clone)]
pub struct Material {
    pub name: String,
    pub diffuse: [f32; 3],
    pub diffuse_texname: String,
}

#[derive(Debug)]
pub struct Shader {
    pub name: String,
    pub vertex_source: String,
    pub fragment_source: String,
}

#[derive(Copy, Clone)]
pub struct Vertex8f32 {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub texcoord: [f32; 2],
}

#[derive(Clone)]
pub struct Mesh {
    pub name: String,
    pub vertices: Vec<Vertex8f32>,
    pub material_index: usize,
}

pub struct ImageBlob {
    pub name: String,
    pub image: Vec<u8>,
}

pub struct Scene {
    pub materials: Vec<Material>,
    pub meshes: Vec<Mesh>,
    pub images: Vec<ImageBlob>,
}
<|endoftext|>


<commit_before>//! Contains several types used throughout the library.

use std::fmt;

/// XML parsing error.
///
/// Consists of a row and column reference and a message.
#[deriving(Clone, PartialEq, Eq)]
pub struct Error {
    row: uint,
    col: uint,
    msg: String
}

/// Represents a thing which has a position inside some textual document.
///
/// This trait is implemented by parsers, lexers and errors. It is used primarily to create
/// error objects.
pub trait HasPosition {
    /// Returns a line number inside the document.
    fn row(&self) -> uint;

    /// Returns a column number inside the document.
    fn col(&self) -> uint;
}

impl fmt::Show for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}: {}", self.row + 1, self.col + 1, self.msg)
    }
}

impl HasPosition for Error {
    #[inline]
    fn row(&self) -> uint { self.row }

    #[inline]
    fn col(&self) -> uint { self.col }
}

impl Error {
    /// Creates a new error using position information from the provided
    /// `HasPosition` object and a message.
    #[inline]
    pub fn new<O: HasPosition>(o: &O, msg: String) -> Error {
        Error { row: o.row(), col: o.col(), msg: msg }
    }

    /// Creates a new error using provided position information and a message.
    #[inline]
    pub fn new_full(row: uint, col: uint, msg: String) -> Error {
        Error { row: row, col: col, msg: msg }
    }

    /// Returns a reference to a message which is contained inside this error.
    #[inline]
    pub fn msg<'a>(&'a self) -> &'a str { self.msg.as_slice() }
}

/// XML qualified name.
///
/// Consists of optional prefix, optional namespace and mandatory
/// local name.
#[deriving(Clone, PartialEq, Eq)]
pub struct Name {
    /// An XML namespace prefix.
    ///
    /// This field is always `None` when `namespace` is `None`.
    pub prefix: Option<String>,

    /// An XML namespace identifier.
    pub namespace: Option<String>,

    /// Local (namespace-less) name.
    pub local_name: String
}

impl fmt::Show for Name {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        macro_rules! try_opt(
            ($v:expr) => (
                match $v {
                    Some(e) => try!(e),
                    None => {}
                }
            )
        )

        try_opt!(self.namespace.as_ref().map(|namespace| {
            write!(f, "{{{}}}", namespace)
        }));
        try_opt!(self.prefix.as_ref().map(|prefix| {
            write!(f, "{}:", prefix)
        }));
        write!(f, "{}", self.local_name)
    }
}

impl Name {
    /// Returns a `Name` instance representing plain local name.
    #[inline]
    pub fn new_local(name: &str) -> Name {
        Name {
            local_name: name.to_string(),
            prefix: None,
            namespace: None
        }
    }

    /// Returns a slice with namespace prefix of this name, if it is present.
    pub fn prefix_ref<'a>(&'a self) -> Option<&'a str> {
        match self.prefix {
            None             => None,
            Some(ref prefix) => Some(prefix.as_slice())
        }
    }

    /// Returns a slice with namespace URI of this name, if it is present.
    pub fn namespace_ref<'a>(&'a self) -> Option<&'a str> {
        match self.namespace {
            None                => None,
            Some(ref namespace) => Some(namespace.as_slice())
        }
    }

    pub fn to_str_proper(&self) -> String {
        match self.prefix {
            Some(ref prefix) => format!("{}:{}", prefix, self.local_name),
            None => self.local_name.clone()
        }
    }
}

/// XML element attribute.
///
/// Consistes of a qualified name and a value.
#[deriving(Clone, PartialEq, Eq)]
pub struct Attribute {
    /// Qualified name of the attribute.
    pub name: Name,

    /// Attribute value.
    pub value: String
}

impl Attribute {
    pub fn new_local(name: &str, value: &str) -> Attribute {
        Attribute {
            name: Name::new_local(name),
            value: value.to_string()
        }
    }
}

/// XML version enumeration.
#[deriving(Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML version 1.0.
    Version10,

    /// XML version 1.1.
    Version11
}

impl fmt::Show for XmlVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Version10 => write!(f, "1.0"),
            Version11 => write!(f, "1.1")
        }
    }
}

/// Checks whether the given character is a white space character (`S`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_whitespace_char(c: char) -> bool {
    match c {
        '\x20' | '\x09' | '\x0d' | '\x0a' => true,
        _ => false
    }
}

/// Checks whether the given character is a name start character (`NameStartChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_start_char(c: char) -> bool {
    match c {
        ':' | 'A'..'Z' | '_' | 'a'..'z' |
        '\xC0'..'\xD6' | '\xD8'..'\xF6' | '\xF8'..'\u02FF' |
        '\u0370'..'\u037D' | '\u037F'..'\u1FFF' |
        '\u200C'..'\u200D' | '\u2070'..'\u218F' |
        '\u2C00'..'\u2FEF' | '\u3001'..'\uD7FF' |
        '\uF900'..'\uFDCF' | '\uFDF0'..'\uFFFD' |
        '\U00010000'..'\U000EFFFF' => true,
        _ => false
    }
}

/// Checks whether the given character is a name character (`NameChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_char(c: char) -> bool {
    match c {
        _ if is_name_start_char(c) => true,
        '-' | '.' | '0'..'9' | '\xB7' |
        '\u0300'..'\u03F6' | '\u203F'..'\u2040' => true,
        _ => false
    }
}

/// Parses given string slice into an XML qualified name.
///
/// This function, when finishes sucessfully, always return a qualified
/// name without namespace (`name.namespace == None`). It should be filled later
/// using proper `NamespaceStack`.
///
/// It is supposed that all characters in the argument string are correct
/// as defined by the XML specification. No additional checks except a check
/// for emptiness are done.
pub fn parse_name(name: &str) -> Option<Name> {
    match name.split(':').collect::<Vec<&str>>().as_slice() {
        [prefix, local_name] if !prefix.is_empty() && !local_name.is_empty() =>
            Some(Name { prefix: Some(prefix.to_string()), namespace: None, local_name: local_name.to_string() }),
        [local_name] if !local_name.is_empty() =>
            Some(Name { prefix: None, namespace: None, local_name: local_name.to_string() }),
        _ => None
    }
}

/// Performs escaping of common XML characters.
///
/// This function replaces several important markup characters with their
/// entity equivalents.
///
/// * `<` → `<`
/// * `>` → `>`
/// * `"` → `"`
/// * `'` → `'`
/// * `&` → `&`
///
/// The resulting string is safe to use inside XML attribute values or in
/// PCDATA sections.
pub fn escape_str(s: &str) -> String {
    let mut result = String::with_capacity(s.len());
    for c in s.chars() {
        match c {
            '<'  => result.push_str("<"),
            '>'  => result.push_str(">"),
            '"'  => result.push_str("""),
            '\'' => result.push_str("'"),
            '&'  => result.push_str("&"),
            _    => result.push_char(c)
        }
    }
    result
}

/// Contains additional operations on optional values.
pub trait OptionOps<T> {
    /// Executes given action on an optional value, if it is present. Otherwise
    /// it is a no-op.
    fn execute(&self, action: |&T|);
}

impl<T> OptionOps<T> for Option<T> {
    fn execute(&self, action: |&T|) {
        match *self {
            Some(ref value) => action(value),
            None => {}
        }
    }
}
<commit_msg>Implemented Show for Attribute<commit_after>//! Contains several types used throughout the library.

use std::fmt;

/// XML parsing error.
///
/// Consists of a row and column reference and a message.
#[deriving(Clone, PartialEq, Eq)]
pub struct Error {
    row: uint,
    col: uint,
    msg: String
}

/// Represents a thing which has a position inside some textual document.
///
/// This trait is implemented by parsers, lexers and errors. It is used primarily to create
/// error objects.
pub trait HasPosition {
    /// Returns a line number inside the document.
    fn row(&self) -> uint;

    /// Returns a column number inside the document.
    fn col(&self) -> uint;
}

impl fmt::Show for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}: {}", self.row + 1, self.col + 1, self.msg)
    }
}

impl HasPosition for Error {
    #[inline]
    fn row(&self) -> uint { self.row }

    #[inline]
    fn col(&self) -> uint { self.col }
}

impl Error {
    /// Creates a new error using position information from the provided
    /// `HasPosition` object and a message.
    #[inline]
    pub fn new<O: HasPosition>(o: &O, msg: String) -> Error {
        Error { row: o.row(), col: o.col(), msg: msg }
    }

    /// Creates a new error using provided position information and a message.
    #[inline]
    pub fn new_full(row: uint, col: uint, msg: String) -> Error {
        Error { row: row, col: col, msg: msg }
    }

    /// Returns a reference to a message which is contained inside this error.
    #[inline]
    pub fn msg<'a>(&'a self) -> &'a str { self.msg.as_slice() }
}

/// XML qualified name.
///
/// Consists of optional prefix, optional namespace and mandatory
/// local name.
#[deriving(Clone, PartialEq, Eq)]
pub struct Name {
    /// An XML namespace prefix.
    ///
    /// This field is always `None` when `namespace` is `None`.
    pub prefix: Option<String>,

    /// An XML namespace identifier.
    pub namespace: Option<String>,

    /// Local (namespace-less) name.
    pub local_name: String
}

impl fmt::Show for Name {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        macro_rules! try_opt(
            ($v:expr) => (
                match $v {
                    Some(e) => try!(e),
                    None => {}
                }
            )
        )

        try_opt!(self.namespace.as_ref().map(|namespace| {
            write!(f, "{{{}}}", namespace)
        }));
        try_opt!(self.prefix.as_ref().map(|prefix| {
            write!(f, "{}:", prefix)
        }));
        write!(f, "{}", self.local_name)
    }
}

impl Name {
    /// Returns a `Name` instance representing plain local name.
    #[inline]
    pub fn new_local(name: &str) -> Name {
        Name {
            local_name: name.to_string(),
            prefix: None,
            namespace: None
        }
    }

    /// Returns a `Name` instance representing qualified name with the
    /// given prefix and namespace URI.
    #[inline]
    pub fn new(name: &str, prefix: &str, namespace: &str) -> Name {
        Name {
            local_name: name.to_string(),
            prefix: Some(prefix.to_string()),
            namespace: Some(namespace.to_string())
        }
    }

    /// Returns a slice with namespace prefix of this name, if it is present.
    pub fn prefix_ref<'a>(&'a self) -> Option<&'a str> {
        match self.prefix {
            None             => None,
            Some(ref prefix) => Some(prefix.as_slice())
        }
    }

    /// Returns a slice with namespace URI of this name, if it is present.
    pub fn namespace_ref<'a>(&'a self) -> Option<&'a str> {
        match self.namespace {
            None                => None,
            Some(ref namespace) => Some(namespace.as_slice())
        }
    }

    /// Returns correct XML representation of this local name and prefix.
    ///
    /// This method is different from autoderived `to_string()` because it does not
    /// include namespace URI in the result.
    pub fn to_str_proper(&self) -> String {
        match self.prefix {
            Some(ref prefix) => format!("{}:{}", prefix, self.local_name),
            None => self.local_name.clone()
        }
    }
}

/// XML element attribute.
///
/// Consistes of a qualified name and a value.
#[deriving(Clone, PartialEq, Eq)]
pub struct Attribute {
    /// Qualified name of the attribute.
    pub name: Name,

    /// Attribute value.
    pub value: String
}

impl fmt::Show for Attribute {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}=\"{}\"", self.name, escape_str(self.value.as_slice()))
    }
}

impl Attribute {
    /// Returns an `Attribute` instance with the given qualified name and value.
    #[inline]
    pub fn new(name: Name, value: &str) -> Attribute {
        Attribute { name: name, value: value.to_string() }
    }

    /// Returns an `Attribute` instance with plain local name and the given value.
    #[inline]
    pub fn new_local(name: &str, value: &str) -> Attribute {
        Attribute {
            name: Name::new_local(name),
            value: value.to_string()
        }
    }
}

/// XML version enumeration.
#[deriving(Clone, PartialEq, Eq)]
pub enum XmlVersion {
    /// XML version 1.0.
    Version10,

    /// XML version 1.1.
    Version11
}

impl fmt::Show for XmlVersion {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Version10 => write!(f, "1.0"),
            Version11 => write!(f, "1.1")
        }
    }
}

/// Checks whether the given character is a white space character (`S`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_whitespace_char(c: char) -> bool {
    match c {
        '\x20' | '\x09' | '\x0d' | '\x0a' => true,
        _ => false
    }
}

/// Checks whether the given character is a name start character (`NameStartChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_start_char(c: char) -> bool {
    match c {
        ':' | 'A'..'Z' | '_' | 'a'..'z' |
        '\xC0'..'\xD6' | '\xD8'..'\xF6' | '\xF8'..'\u02FF' |
        '\u0370'..'\u037D' | '\u037F'..'\u1FFF' |
        '\u200C'..'\u200D' | '\u2070'..'\u218F' |
        '\u2C00'..'\u2FEF' | '\u3001'..'\uD7FF' |
        '\uF900'..'\uFDCF' | '\uFDF0'..'\uFFFD' |
        '\U00010000'..'\U000EFFFF' => true,
        _ => false
    }
}

/// Checks whether the given character is a name character (`NameChar`)
/// as is defined by XML 1.1 specification, [section 2.3][1].
///
/// [1]: http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-common-syn
pub fn is_name_char(c: char) -> bool {
    match c {
        _ if is_name_start_char(c) => true,
        '-' | '.' | '0'..'9' | '\xB7' |
        '\u0300'..'\u03F6' | '\u203F'..'\u2040' => true,
        _ => false
    }
}

/// Parses given string slice into an XML qualified name.
///
/// This function, when finishes sucessfully, always return a qualified
/// name without namespace (`name.namespace == None`). It should be filled later
/// using proper `NamespaceStack`.
///
/// It is supposed that all characters in the argument string are correct
/// as defined by the XML specification. No additional checks except a check
/// for emptiness are done.
pub fn parse_name(name: &str) -> Option<Name> {
    match name.split(':').collect::<Vec<&str>>().as_slice() {
        [prefix, local_name] if !prefix.is_empty() && !local_name.is_empty() =>
            Some(Name { prefix: Some(prefix.to_string()), namespace: None, local_name: local_name.to_string() }),
        [local_name] if !local_name.is_empty() =>
            Some(Name { prefix: None, namespace: None, local_name: local_name.to_string() }),
        _ => None
    }
}

/// Performs escaping of common XML characters.
///
/// This function replaces several important markup characters with their
/// entity equivalents.
///
/// * `<` → `<`
/// * `>` → `>`
/// * `"` → `"`
/// * `'` → `'`
/// * `&` → `&`
///
/// The resulting string is safe to use inside XML attribute values or in
/// PCDATA sections.
pub fn escape_str(s: &str) -> String {
    let mut result = String::with_capacity(s.len());
    for c in s.chars() {
        match c {
            '<'  => result.push_str("<"),
            '>'  => result.push_str(">"),
            '"'  => result.push_str("""),
            '\'' => result.push_str("'"),
            '&'  => result.push_str("&"),
            _    => result.push_char(c)
        }
    }
    result
}

/// Contains additional operations on optional values.
pub trait OptionOps<T> {
    /// Executes given action on an optional value, if it is present. Otherwise
    /// it is a no-op.
    fn execute(&self, action: |&T|);
}

impl<T> OptionOps<T> for Option<T> {
    fn execute(&self, action: |&T|) {
        match *self {
            Some(ref value) => action(value),
            None => {}
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Name, Attribute};

    #[test]
    fn attribute_show() {
        let attr = Attribute::new(
            Name::new("attribute", "n", "urn:namespace"),
            "its value with > & \" ' < weird symbols"
        );
        assert_eq!(
            attr.to_string().as_slice(),
            "{urn:namespace}n:attribute=\"its value with > & " ' < weird symbols\""
        )
    }
}
<|endoftext|>