<commit_before>use std::io::{Read, Write};
use std::net::TcpStream;
use winapi;

use schannel_cred::{Direction, Protocol, Algorithm, SchannelCred};
use tls_stream;

#[test]
fn basic() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn invalid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Rc2, Algorithm::Ecdsa])
        .acquire(Direction::Outbound);
    assert_eq!(creds.err().unwrap().raw_os_error().unwrap(),
               winapi::SEC_E_ALGORITHM_MISMATCH as i32);
}

#[test]
fn valid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Aes128, Algorithm::Ecdsa])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
#[ignore] // google's inconsistent about disallowing sslv3
fn invalid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Ssl3])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::SEC_E_UNSUPPORTED_FUNCTION as i32);
}

#[test]
fn valid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Tls12])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn expired_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("expired.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("expired.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_EXPIRED as i32);
}

#[test]
fn self_signed_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_UNTRUSTEDROOT as i32);
}

#[test]
fn wrong_host_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("wrong.host.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("wrong.host.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_CN_NO_MATCH as i32);
}

#[test]
fn shutdown() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.shutdown().unwrap();
}
<commit_msg>Add test<commit_after>use std::io::{Read, Write};
use std::net::TcpStream;
use winapi;

use schannel_cred::{Direction, Protocol, Algorithm, SchannelCred};
use tls_stream;

#[test]
fn basic() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn invalid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Rc2, Algorithm::Ecdsa])
        .acquire(Direction::Outbound);
    assert_eq!(creds.err().unwrap().raw_os_error().unwrap(),
               winapi::SEC_E_ALGORITHM_MISMATCH as i32);
}

#[test]
fn valid_algorithms() {
    let creds = SchannelCred::builder()
        .supported_algorithms(&[Algorithm::Aes128, Algorithm::Ecdsa])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
#[ignore] // google's inconsistent about disallowing sslv3
fn invalid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Ssl3])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::SEC_E_UNSUPPORTED_FUNCTION as i32);
}

#[test]
fn valid_protocol() {
    let creds = SchannelCred::builder()
        .enabled_protocols(&[Protocol::Tls12])
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
    let mut out = vec![];
    stream.read_to_end(&mut out).unwrap();
    assert!(out.starts_with(b"HTTP/1.0 200 OK"));
    assert!(out.ends_with(b""));
}

#[test]
fn expired_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("expired.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("expired.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_EXPIRED as i32);
}

#[test]
fn self_signed_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_UNTRUSTEDROOT as i32);
}

#[test]
fn wrong_host_cert() {
    let creds = SchannelCred::builder()
        .acquire(Direction::Outbound)
        .unwrap();
    let stream = TcpStream::connect("wrong.host.badssl.com:443").unwrap();
    let err = tls_stream::Builder::new()
        .domain("wrong.host.badssl.com")
        .initialize(creds, stream)
        .err()
        .unwrap();
    assert_eq!(err.raw_os_error().unwrap(), winapi::CERT_E_CN_NO_MATCH as i32);
}

#[test]
fn shutdown() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("google.com:443").unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("google.com")
        .initialize(creds, stream)
        .unwrap();
    stream.shutdown().unwrap();
}

#[test]
fn validation_failure_is_permanent() {
    let creds = SchannelCred::builder().acquire(Direction::Outbound).unwrap();
    let stream = TcpStream::connect("self-signed.badssl.com:443").unwrap();
    // temporarily switch to nonblocking to allow us to construct the stream
    // without validating
    stream.set_nonblocking(true).unwrap();
    let mut stream = tls_stream::Builder::new()
        .domain("self-signed.badssl.com")
        .initialize(creds, stream)
        .unwrap();
    stream.get_ref().set_nonblocking(false).unwrap();
    assert!(stream.write(b"hi").is_err());
    assert!(stream.write(b"hi").is_err());
}<|endoftext|>


<commit_before>// Standard Imports
use std::io::Cursor;

// Internal Imports
use datagram::Datagram;

// External Test Imports
#[cfg(test)]
use rustc_serialize::hex::FromHex;

const RAW_TEST_DATA: &'static str = "this data is redacted";

#[test]
fn test_decode_datagram() {

    let hex_data = RAW_TEST_DATA.clone().from_hex().unwrap();
    let mut data = Cursor::new(hex_data);

    let d: Datagram = ::utils::Decodeable::read_and_decode(&mut data).unwrap();
    // TODO: Add more tests here.
    assert_eq!(d.sample_record.len(), 6);
}

#[test]
fn test_decode_string() {
    struct TestDecodeStringCase {
        raw_test_data: &'static str,
        result: &'static str,
    };

    let test_cases: Vec<TestDecodeStringCase> = vec![
        TestDecodeStringCase{raw_test_data: "00000006666f6f626172", result: "foobar"},
    ];

    for case in test_cases {
        let mut data = Cursor::new(case.raw_test_data.clone().from_hex().unwrap());
        let res: String = ::utils::Decodeable::read_and_decode(&mut data).unwrap();

        assert_eq!(case.result, res);
    }
}
<commit_msg>Comment out test that is broken<commit_after>// Standard Imports
use std::io::Cursor;

// Internal Imports
use datagram::Datagram;

// External Test Imports
#[cfg(test)]
use rustc_serialize::hex::FromHex;

// const RAW_TEST_DATA: &'static str = "this data is redacted";
//
// #[test]
// fn test_decode_datagram() {
//
// let hex_data = RAW_TEST_DATA.clone().from_hex().unwrap();
// let mut data = Cursor::new(hex_data);
//
// let d: Datagram = ::utils::Decodeable::read_and_decode(&mut data).unwrap();
// TODO: Add more tests here.
// assert_eq!(d.sample_record.len(), 6);
// }

#[test]
fn test_decode_string() {
    struct TestDecodeStringCase {
        raw_test_data: &'static str,
        result: &'static str,
    };

    let test_cases: Vec<TestDecodeStringCase> = vec![
        TestDecodeStringCase{raw_test_data: "00000006666f6f626172", result: "foobar"},
    ];

    for case in test_cases {
        let mut data = Cursor::new(case.raw_test_data.clone().from_hex().unwrap());
        let res: String = ::utils::Decodeable::read_and_decode(&mut data).unwrap();

        assert_eq!(case.result, res);
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io;
use std::error::Error;
use std::process::Command;
use std::fs;
use std::path::PathBuf;

use devicemapper::{DM, Device, DmFlags, DevId, DM_SUSPEND};
use uuid::Uuid;
use nix::sys::stat::{mknod, umask, Mode, S_IFBLK, S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP};

use types::{Sectors, DataBlocks, FroyoError, FroyoResult};
use raid::{RaidSegment, RaidLinearDev, RaidLinearDevSave};
use util::{clear_dev, setup_dm_dev};
use consts::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThinPoolDevSave {
    pub data_block_size: Sectors,
    pub low_water_blocks: DataBlocks,
    pub meta_dev: RaidLinearDevSave,
    pub data_dev: RaidLinearDevSave,
}

#[derive(Debug, Clone)]
pub struct ThinPoolDev {
    dm_name: String,
    dev: Device,
    data_block_size: Sectors,
    low_water_blocks: DataBlocks,
    params: String,
    meta_dev: RaidLinearDev,
    data_dev: RaidLinearDev,
}

#[derive(Debug, Clone, Copy)]
pub struct ThinPoolBlockUsage {
    pub used_meta: u64,
    pub total_meta: u64,
    pub used_data: DataBlocks,
    pub total_data: DataBlocks,
}

pub enum ThinPoolStatus {
    Good((ThinPoolWorkingStatus, ThinPoolBlockUsage)),
    Fail,
}

pub enum ThinPoolWorkingStatus {
    Good,
    ReadOnly,
    OutOfSpace,
    NeedsCheck,
}

impl ThinPoolDev {
    pub fn new(dm: &DM,
               name: &str,
               meta_segs: Vec<RaidSegment>,
               data_segs: Vec<RaidSegment>)
               -> io::Result<ThinPoolDev> {
        // meta
        let meta_name = format!("thin-meta-{}", name);
        let meta_raid_dev = try!(RaidLinearDev::create(
            dm,
            &meta_name,
            &Uuid::new_v4().to_simple_string(),
            meta_segs));

        try!(clear_dev(&meta_raid_dev.dev));

        // data
        let data_name = format!("thin-data-{}", name);
        let data_raid_dev = try!(RaidLinearDev::create(
            dm,
            &data_name,
            &Uuid::new_v4().to_simple_string(),
            data_segs));

        let data_block_size = Sectors::new(2048); // 1MiB
        let low_water_blocks = DataBlocks::new(512); // 512MiB

        ThinPoolDev::create(
            dm,
            name,
            data_block_size,
            low_water_blocks,
            meta_raid_dev,
            data_raid_dev)
    }

    pub fn create(
        dm: &DM,
        name: &str,
        data_block_size: Sectors,
        low_water_blocks: DataBlocks,
        meta_raid_dev: RaidLinearDev,
        data_raid_dev: RaidLinearDev)
        -> io::Result<ThinPoolDev> {

        let params = format!("{}:{} {}:{} {} {}",
                             meta_raid_dev.dev.major,
                             meta_raid_dev.dev.minor,
                             data_raid_dev.dev.major,
                             data_raid_dev.dev.minor,
                             *data_block_size,
                             *low_water_blocks);
        let table = [(0u64, *data_raid_dev.length(), "thin-pool", &*params)];

        let dm_name = format!("froyo-thin-pool-{}", name);
        let pool_dev = try!(setup_dm_dev(dm, &dm_name, &table));

        Ok(ThinPoolDev {
            dm_name: dm_name,
            dev: pool_dev,
            data_block_size: data_block_size,
            low_water_blocks: low_water_blocks,
            params: params.clone(),
            meta_dev: meta_raid_dev,
            data_dev: data_raid_dev,
        })
    }

    pub fn to_save(&self) -> ThinPoolDevSave {
        ThinPoolDevSave {
            data_block_size: self.data_block_size,
            low_water_blocks: self.low_water_blocks,
            meta_dev: self.meta_dev.to_save(),
            data_dev: self.data_dev.to_save(),
        }
    }

    pub fn status(&self) -> FroyoResult<ThinPoolStatus> {
        let dm = try!(DM::new());

        let (_, mut status) = try!(
            dm.table_status(&DevId::Name(&self.dm_name), DmFlags::empty()));

        if status.len() != 1 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Expected 1 line from thin pool status")))
        }

        let status_line = status.pop().unwrap().3;
        if status_line.starts_with("Fail") {
            return Ok(ThinPoolStatus::Fail)
        }

        let status_vals = status_line.split(' ').collect::<Vec<_>>();
        if status_vals.len() < 8 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned too few values from thin pool status")))
        }

        let usage = {
            let meta_vals = status_vals[1].split('/').collect::<Vec<_>>();
            let data_vals = status_vals[2].split('/').collect::<Vec<_>>();
            ThinPoolBlockUsage {
                used_meta: meta_vals[0].parse::<u64>().unwrap(),
                total_meta: meta_vals[1].parse::<u64>().unwrap(),
                used_data: DataBlocks::new(data_vals[0].parse::<u64>().unwrap()),
                total_data: DataBlocks::new(data_vals[1].parse::<u64>().unwrap()),
            }
        };

        match status_vals[7] {
            "-" => {},
            "needs_check" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::NeedsCheck, usage))),
            _ => return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned unexpected value in thin pool status")))
        }

        match status_vals[4] {
            "rw" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::Good, usage))),
            "ro" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::ReadOnly, usage))),
            "out_of_data_space" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::OutOfSpace, usage))),
            _ => return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned unexpected value in thin pool status")))
        }
    }

    // return size of a data block in bytes
    pub fn data_block_size(&self) -> u64 {
        *self.data_block_size * SECTOR_SIZE
    }

    pub fn sectors_to_blocks(&self, sectors: Sectors) -> DataBlocks {
        DataBlocks::new(*sectors / *self.data_block_size)
    }

    pub fn blocks_to_sectors(&self, blocks: DataBlocks) -> Sectors {
        Sectors::new(*blocks * *self.data_block_size)
    }

    pub fn extend_data_dev(&mut self, segs: Vec<RaidSegment>)
                           -> FroyoResult<()> {
        try!(self.data_dev.extend(segs));
        try!(self.dm_reload());
        Ok(())
    }

    pub fn extend_meta_dev(&mut self, segs: Vec<RaidSegment>)
                           -> FroyoResult<()> {
        try!(self.meta_dev.extend(segs));
        try!(self.dm_reload());
        Ok(())
    }

    fn dm_reload(&self) -> FroyoResult<()> {
        let dm = try!(DM::new());
        let id = &DevId::Name(&self.dm_name);

        let table = [(0u64, *self.data_dev.length(), "thin-pool", &*self.params)];

        try!(dm.table_load(id, &table));
        try!(dm.device_suspend(id, DM_SUSPEND));
        try!(dm.device_suspend(id, DmFlags::empty()));
        Ok(())
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThinDevSave {
    pub thin_number: u32,
    pub size: Sectors,
}

#[derive(Debug, Clone)]
pub struct ThinDev {
    dev: Device,
    thin_number: u32,
    pub size: Sectors,
    dm_name: String,
}

pub enum ThinStatus {
    Good(Sectors),
    Fail,
}

impl ThinDev {
    pub fn new(
        dm: &DM,
        name: &str,
        thin_number: u32,
        size: Sectors,
        pool_dev: &ThinPoolDev)
        -> FroyoResult<ThinDev> {

        try!(dm.target_msg(&DevId::Name(&pool_dev.dm_name),
                           0, &format!("create_thin {}", thin_number)));

        let mut td = try!(ThinDev::create(
            dm,
            name,
            thin_number,
            size,
            pool_dev));

        try!(td.create_devnode(name));
        try!(td.create_fs(name));

        Ok(td)
    }

    pub fn create(
        dm: &DM,
        name: &str,
        thin_number: u32,
        size: Sectors,
        pool_dev: &ThinPoolDev)
        -> FroyoResult<ThinDev> {

        let params = format!("{}:{} {}", pool_dev.dev.major,
                             pool_dev.dev.minor, thin_number);
        let table = [(0u64, *size, "thin", params)];

        let dm_name = format!("froyo-thin-{}-{}", name, thin_number);
        let thin_dev = try!(setup_dm_dev(dm, &dm_name, &table));

        Ok(ThinDev {
            dev: thin_dev,
            thin_number: thin_number,
            size: size,
            dm_name: dm_name,
        })
    }

    pub fn to_save(&self) -> ThinDevSave {
        ThinDevSave {
            thin_number: self.thin_number,
            size: self.size,
        }
    }

    pub fn status(&self) -> FroyoResult<ThinStatus> {
        let dm = try!(DM::new());

        let (_, mut status) = try!(
            dm.table_status(&DevId::Name(&self.dm_name), DmFlags::empty()));

        if status.len() != 1 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Expected 1 line from thin status")))
        }

        // We should either get 1 line or the kernel is broken
        let status_line = status.pop().unwrap().3;
        if status_line.starts_with("Fail") {
            return Ok(ThinStatus::Fail)
        }
        let status_vals = status_line.split(' ').collect::<Vec<_>>();

        Ok(ThinStatus::Good(Sectors::new(status_vals[0].parse::<u64>().unwrap())))
    }

    fn create_devnode(&mut self, name: &str) -> FroyoResult<()> {
        let mut pathbuf = PathBuf::from("/dev/froyo");

        match fs::create_dir(&pathbuf) {
            Ok(()) => {},
            Err(e) => {
                match e.kind() {
                    io::ErrorKind::AlreadyExists => {},
                    _ => return Err(FroyoError::Io(e)),
                }
            }
        }

        pathbuf.push(name);

        let old_umask = umask(Mode::empty());
        match mknod(&pathbuf, S_IFBLK, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, self.dev.into()) {
            Ok(()) => { umask(old_umask); },
            Err(e) => {
                umask(old_umask);
                return Err(FroyoError::Nix(e))
            },
        };

        Ok(())
    }

    fn create_fs(&mut self, name: &str) -> FroyoResult<()> {
        let dev_name = format!("/dev/froyo/{}", name);
        let output = try!(Command::new("mkfs.xfs")
                          .arg("-f")
                          .arg(&dev_name)
                          .output());

        if output.status.success(){
            dbgp!("Created xfs filesystem on {}", dev_name)
        } else {
            println!("err {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }
}
<commit_msg>Tidy some error handling and whitespace<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::io;
use std::error::Error;
use std::process::Command;
use std::fs;
use std::path::PathBuf;

use devicemapper::{DM, Device, DmFlags, DevId, DM_SUSPEND};
use uuid::Uuid;
use nix::sys::stat::{mknod, umask, Mode, S_IFBLK, S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP};

use types::{Sectors, DataBlocks, FroyoError, FroyoResult};
use raid::{RaidSegment, RaidLinearDev, RaidLinearDevSave};
use util::{clear_dev, setup_dm_dev};
use consts::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThinPoolDevSave {
    pub data_block_size: Sectors,
    pub low_water_blocks: DataBlocks,
    pub meta_dev: RaidLinearDevSave,
    pub data_dev: RaidLinearDevSave,
}

#[derive(Debug, Clone)]
pub struct ThinPoolDev {
    dm_name: String,
    dev: Device,
    data_block_size: Sectors,
    low_water_blocks: DataBlocks,
    params: String,
    meta_dev: RaidLinearDev,
    data_dev: RaidLinearDev,
}

#[derive(Debug, Clone, Copy)]
pub struct ThinPoolBlockUsage {
    pub used_meta: u64,
    pub total_meta: u64,
    pub used_data: DataBlocks,
    pub total_data: DataBlocks,
}

pub enum ThinPoolStatus {
    Good((ThinPoolWorkingStatus, ThinPoolBlockUsage)),
    Fail,
}

pub enum ThinPoolWorkingStatus {
    Good,
    ReadOnly,
    OutOfSpace,
    NeedsCheck,
}

impl ThinPoolDev {
    pub fn new(dm: &DM,
               name: &str,
               meta_segs: Vec<RaidSegment>,
               data_segs: Vec<RaidSegment>)
               -> io::Result<ThinPoolDev> {
        // meta
        let meta_name = format!("thin-meta-{}", name);
        let meta_raid_dev = try!(RaidLinearDev::create(
            dm,
            &meta_name,
            &Uuid::new_v4().to_simple_string(),
            meta_segs));

        try!(clear_dev(&meta_raid_dev.dev));

        // data
        let data_name = format!("thin-data-{}", name);
        let data_raid_dev = try!(RaidLinearDev::create(
            dm,
            &data_name,
            &Uuid::new_v4().to_simple_string(),
            data_segs));

        let data_block_size = Sectors::new(2048); // 1MiB
        let low_water_blocks = DataBlocks::new(512); // 512MiB

        ThinPoolDev::create(
            dm,
            name,
            data_block_size,
            low_water_blocks,
            meta_raid_dev,
            data_raid_dev)
    }

    pub fn create(
        dm: &DM,
        name: &str,
        data_block_size: Sectors,
        low_water_blocks: DataBlocks,
        meta_raid_dev: RaidLinearDev,
        data_raid_dev: RaidLinearDev)
        -> io::Result<ThinPoolDev> {

        let params = format!("{}:{} {}:{} {} {}",
                             meta_raid_dev.dev.major,
                             meta_raid_dev.dev.minor,
                             data_raid_dev.dev.major,
                             data_raid_dev.dev.minor,
                             *data_block_size,
                             *low_water_blocks);
        let table = [(0u64, *data_raid_dev.length(), "thin-pool", &*params)];

        let dm_name = format!("froyo-thin-pool-{}", name);
        let pool_dev = try!(setup_dm_dev(dm, &dm_name, &table));

        Ok(ThinPoolDev {
            dm_name: dm_name,
            dev: pool_dev,
            data_block_size: data_block_size,
            low_water_blocks: low_water_blocks,
            params: params.clone(),
            meta_dev: meta_raid_dev,
            data_dev: data_raid_dev,
        })
    }

    pub fn to_save(&self) -> ThinPoolDevSave {
        ThinPoolDevSave {
            data_block_size: self.data_block_size,
            low_water_blocks: self.low_water_blocks,
            meta_dev: self.meta_dev.to_save(),
            data_dev: self.data_dev.to_save(),
        }
    }

    pub fn status(&self) -> FroyoResult<ThinPoolStatus> {
        let dm = try!(DM::new());

        let (_, mut status) = try!(
            dm.table_status(&DevId::Name(&self.dm_name), DmFlags::empty()));

        if status.len() != 1 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Expected 1 line from thin pool status")))
        }

        let status_line = status.pop().unwrap().3;
        if status_line.starts_with("Fail") {
            return Ok(ThinPoolStatus::Fail)
        }

        let status_vals = status_line.split(' ').collect::<Vec<_>>();
        if status_vals.len() < 8 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned too few values from thin pool status")))
        }

        let usage = {
            let meta_vals = status_vals[1].split('/').collect::<Vec<_>>();
            let data_vals = status_vals[2].split('/').collect::<Vec<_>>();
            ThinPoolBlockUsage {
                used_meta: meta_vals[0].parse::<u64>().unwrap(),
                total_meta: meta_vals[1].parse::<u64>().unwrap(),
                used_data: DataBlocks::new(data_vals[0].parse::<u64>().unwrap()),
                total_data: DataBlocks::new(data_vals[1].parse::<u64>().unwrap()),
            }
        };

        match status_vals[7] {
            "-" => {},
            "needs_check" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::NeedsCheck, usage))),
            _ => return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned unexpected value in thin pool status")))
        }

        match status_vals[4] {
            "rw" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::Good, usage))),
            "ro" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::ReadOnly, usage))),
            "out_of_data_space" => return Ok(ThinPoolStatus::Good(
                (ThinPoolWorkingStatus::OutOfSpace, usage))),
            _ => return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Kernel returned unexpected value in thin pool status")))
        }
    }

    // return size of a data block in bytes
    pub fn data_block_size(&self) -> u64 {
        *self.data_block_size * SECTOR_SIZE
    }

    pub fn sectors_to_blocks(&self, sectors: Sectors) -> DataBlocks {
        DataBlocks::new(*sectors / *self.data_block_size)
    }

    pub fn blocks_to_sectors(&self, blocks: DataBlocks) -> Sectors {
        Sectors::new(*blocks * *self.data_block_size)
    }

    pub fn extend_data_dev(&mut self, segs: Vec<RaidSegment>)
                           -> FroyoResult<()> {
        try!(self.data_dev.extend(segs));
        try!(self.dm_reload());
        Ok(())
    }

    pub fn extend_meta_dev(&mut self, segs: Vec<RaidSegment>)
                           -> FroyoResult<()> {
        try!(self.meta_dev.extend(segs));
        try!(self.dm_reload());
        Ok(())
    }

    fn dm_reload(&self) -> FroyoResult<()> {
        let dm = try!(DM::new());
        let id = &DevId::Name(&self.dm_name);

        let table = [(0u64, *self.data_dev.length(), "thin-pool", &*self.params)];

        try!(dm.table_load(id, &table));
        try!(dm.device_suspend(id, DM_SUSPEND));
        try!(dm.device_suspend(id, DmFlags::empty()));
        Ok(())
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThinDevSave {
    pub thin_number: u32,
    pub size: Sectors,
}

#[derive(Debug, Clone)]
pub struct ThinDev {
    dev: Device,
    thin_number: u32,
    pub size: Sectors,
    dm_name: String,
}

pub enum ThinStatus {
    Good(Sectors),
    Fail,
}

impl ThinDev {
    pub fn new(
        dm: &DM,
        name: &str,
        thin_number: u32,
        size: Sectors,
        pool_dev: &ThinPoolDev)
        -> FroyoResult<ThinDev> {

        try!(dm.target_msg(&DevId::Name(&pool_dev.dm_name),
                           0, &format!("create_thin {}", thin_number)));

        let mut td = try!(ThinDev::create(
            dm,
            name,
            thin_number,
            size,
            pool_dev));

        try!(td.create_devnode(name));
        try!(td.create_fs(name));

        Ok(td)
    }

    pub fn create(
        dm: &DM,
        name: &str,
        thin_number: u32,
        size: Sectors,
        pool_dev: &ThinPoolDev)
        -> FroyoResult<ThinDev> {

        let params = format!("{}:{} {}", pool_dev.dev.major,
                             pool_dev.dev.minor, thin_number);
        let table = [(0u64, *size, "thin", params)];

        let dm_name = format!("froyo-thin-{}-{}", name, thin_number);
        let thin_dev = try!(setup_dm_dev(dm, &dm_name, &table));

        Ok(ThinDev {
            dev: thin_dev,
            thin_number: thin_number,
            size: size,
            dm_name: dm_name,
        })
    }

    pub fn to_save(&self) -> ThinDevSave {
        ThinDevSave {
            thin_number: self.thin_number,
            size: self.size,
        }
    }

    pub fn status(&self) -> FroyoResult<ThinStatus> {
        let dm = try!(DM::new());

        let (_, mut status) = try!(
            dm.table_status(&DevId::Name(&self.dm_name), DmFlags::empty()));

        if status.len() != 1 {
            return Err(FroyoError::Io(io::Error::new(
                io::ErrorKind::InvalidData,
                "Expected 1 line from thin status")))
        }

        // We should either get 1 line or the kernel is broken
        let status_line = status.pop().unwrap().3;
        if status_line.starts_with("Fail") {
            return Ok(ThinStatus::Fail)
        }
        let status_vals = status_line.split(' ').collect::<Vec<_>>();

        Ok(ThinStatus::Good(Sectors::new(
            status_vals[0].parse::<u64>().unwrap())))
    }

    fn create_devnode(&mut self, name: &str) -> FroyoResult<()> {
        let mut pathbuf = PathBuf::from("/dev/froyo");

        match fs::create_dir(&pathbuf) {
            Ok(()) => {},
            Err(e) => {
                match e.kind() {
                    io::ErrorKind::AlreadyExists => {},
                    _ => return Err(FroyoError::Io(e)),
                }
            }
        }

        pathbuf.push(name);

        let old_umask = umask(Mode::empty());
        let res = mknod(&pathbuf,
                    S_IFBLK,
                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
                    self.dev.into());
        umask(old_umask);
        if let Err(e) = res {
            return Err(FroyoError::Nix(e))
        }

        Ok(())
    }

    fn create_fs(&mut self, name: &str) -> FroyoResult<()> {
        let dev_name = format!("/dev/froyo/{}", name);
        let output = try!(Command::new("mkfs.xfs")
                          .arg("-f")
                          .arg(&dev_name)
                          .output());

        if output.status.success(){
            dbgp!("Created xfs filesystem on {}", dev_name)
        } else {
            println!("err {}", String::from_utf8_lossy(&output.stderr));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! STUN messages.
//!
//! > STUN is a client-server protocol.  It supports two types of
//! > transactions. One is a **request/response** transaction in which a
//! > client sends a **request** to a server, and the server returns a
//! > **response**. The second is an **indication** transaction in which either
//! > agent -- client or server -- sends an indication that generates no
//! > response. Both types of transactions include a transaction ID, which
//! > is a randomly selected 96-bit number.  For **request/response**
//! > transactions, this transaction ID allows the client to associate the
//! > response with the request that generated it; for indications, the
//! > transaction ID serves as a debugging aid.
//! >
//! > All STUN messages start with a fixed header that includes a method, a
//! > class, and the transaction ID.  The method indicates which of the
//! > various requests or indications this is; this specification defines
//! > just one method, Binding, but other methods are expected to be
//! > defined in other documents.  The class indicates whether this is a
//! > **request**, a **success response**, an **error response**, or an **indication**.
//! > Following the fixed header comes zero or more attributes, which are
//! > Type-Length-Value extensions that convey additional information for
//! > the specific message.
//! >
//! > [RFC 5389 -- 3. Overview of Operation]
//!
//! [RFC 5389 -- 3. Overview of Operation]: https://tools.ietf.org/html/rfc5389#section-3
use rand;
use std;
use stun_codec::rfc5389::attributes::ErrorCode;
use stun_codec::{Attribute, Message, MessageClass, Method, TransactionId};

pub use error::{MessageError, MessageErrorKind};

/// A specialized `Result` type for message-level operations.
pub type MessageResult<T> = Result<T, MessageError>;

/// Invalid message.
#[derive(Debug, Clone)]
pub struct InvalidMessage {
    method: Method,
    class: MessageClass,
    transaction_id: TransactionId,
    error: MessageError,
}
impl InvalidMessage {
    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.method
    }

    /// Returns the class of the message.
    pub fn class(&self) -> MessageClass {
        self.class
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.transaction_id
    }

    /// Returns a reference to the error object that describes why the message is invalid.
    pub fn error(&self) -> &MessageError {
        &self.error
    }

    pub(crate) fn new(
        method: Method,
        class: MessageClass,
        transaction_id: TransactionId,
        error: MessageError,
    ) -> Self {
        InvalidMessage {
            method,
            class,
            transaction_id,
            error,
        }
    }
}

/// Response message.
pub type Response<A> = std::result::Result<SuccessResponse<A>, ErrorResponse<A>>;

/// Request message.
#[derive(Debug, Clone)]
pub struct Request<A>(Message<A>);
impl<A: Attribute> Request<A> {
    /// Makes a new request message.
    pub fn new(method: Method) -> Self {
        Request(Message::new(
            MessageClass::Request,
            method,
            TransactionId::new(rand::random()),
        ))
    }

    /// Converts `Message` to `Request`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::Request`,
    /// this function will return a `MessageErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `MessageErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::Request,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;
        Ok(Request(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for Request<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for Request<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

/// Indication message.
#[derive(Debug, Clone)]
pub struct Indication<A>(Message<A>);
impl<A: Attribute> Indication<A> {
    /// Makes a new indication message.
    pub fn new(method: Method) -> Self {
        Indication(Message::new(
            MessageClass::Indication,
            method,
            TransactionId::new(rand::random()),
        ))
    }

    /// Converts `Message` to `Indication`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::Indication`,
    /// this function will return a `MessageErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `MessageErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::Indication,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;
        Ok(Indication(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for Indication<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for Indication<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

/// Success response message.
#[derive(Debug, Clone)]
pub struct SuccessResponse<A>(Message<A>);
impl<A: Attribute> SuccessResponse<A> {
    /// Makes a new `SuccessResponse` instance for the success response to the given request.
    pub fn new(request: &Request<A>) -> Self {
        SuccessResponse(Message::new(
            MessageClass::SuccessResponse,
            request.method(),
            request.transaction_id(),
        ))
    }

    /// Converts `Message` to `SuccessResponse`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::SuccessResponse`,
    /// this function will return a `MessageErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `MessageErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::SuccessResponse,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;
        Ok(SuccessResponse(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for SuccessResponse<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for SuccessResponse<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

/// Error response message.
#[derive(Debug, Clone)]
pub struct ErrorResponse<A>(Message<A>);
impl<A: Attribute> ErrorResponse<A> {
    /// Makes a new `ErrorResponse` instance for the error response to the given request.
    pub fn new(request: &Request<A>, error: ErrorCode) -> Self
    where
        A: From<ErrorCode>,
    {
        let mut message = Message::new(
            MessageClass::ErrorResponse,
            request.method(),
            request.transaction_id(),
        );
        message.add_attribute(error.into());
        ErrorResponse(message)
    }

    /// Converts `Message` to `ErrorResponse`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::ErrorResponse` or
    /// the message does not contains an `ErrorCode` attribute,
    /// this function will return a `ErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `ErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::ErrorResponse,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;

        let contains_error_code = message
            .attributes()
            .map(|a| a.get_type())
            .chain(message.unknown_attributes().map(|a| a.get_type()))
            .any(|t| t.as_u16() == ErrorCode::CODEPOINT);
        track_assert!(contains_error_code, MessageErrorKind::InvalidInput);
        Ok(ErrorResponse(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for ErrorResponse<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for ErrorResponse<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

fn check_unknown_attributes<A: Attribute>(message: &Message<A>) -> MessageResult<()> {
    let required_unknowns = message
        .unknown_attributes()
        .filter_map(|a| {
            if a.get_type().is_comprehension_required() {
                Some(a.get_type())
            } else {
                None
            }
        })
        .collect::<Vec<_>>();
    track_assert!(
        required_unknowns.is_empty(),
        MessageErrorKind::UnknownAttributes(required_unknowns)
    );
    Ok(())
}
<commit_msg>Add `get_attribute` methods<commit_after>//! STUN messages.
//!
//! > STUN is a client-server protocol.  It supports two types of
//! > transactions. One is a **request/response** transaction in which a
//! > client sends a **request** to a server, and the server returns a
//! > **response**. The second is an **indication** transaction in which either
//! > agent -- client or server -- sends an indication that generates no
//! > response. Both types of transactions include a transaction ID, which
//! > is a randomly selected 96-bit number.  For **request/response**
//! > transactions, this transaction ID allows the client to associate the
//! > response with the request that generated it; for indications, the
//! > transaction ID serves as a debugging aid.
//! >
//! > All STUN messages start with a fixed header that includes a method, a
//! > class, and the transaction ID.  The method indicates which of the
//! > various requests or indications this is; this specification defines
//! > just one method, Binding, but other methods are expected to be
//! > defined in other documents.  The class indicates whether this is a
//! > **request**, a **success response**, an **error response**, or an **indication**.
//! > Following the fixed header comes zero or more attributes, which are
//! > Type-Length-Value extensions that convey additional information for
//! > the specific message.
//! >
//! > [RFC 5389 -- 3. Overview of Operation]
//!
//! [RFC 5389 -- 3. Overview of Operation]: https://tools.ietf.org/html/rfc5389#section-3
use rand;
use std;
use stun_codec::convert::TryAsRef;
use stun_codec::rfc5389::attributes::ErrorCode;
use stun_codec::{Attribute, Message, MessageClass, Method, TransactionId};

pub use error::{MessageError, MessageErrorKind};

/// A specialized `Result` type for message-level operations.
pub type MessageResult<T> = Result<T, MessageError>;

/// Invalid message.
#[derive(Debug, Clone)]
pub struct InvalidMessage {
    method: Method,
    class: MessageClass,
    transaction_id: TransactionId,
    error: MessageError,
}
impl InvalidMessage {
    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.method
    }

    /// Returns the class of the message.
    pub fn class(&self) -> MessageClass {
        self.class
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.transaction_id
    }

    /// Returns a reference to the error object that describes why the message is invalid.
    pub fn error(&self) -> &MessageError {
        &self.error
    }

    pub(crate) fn new(
        method: Method,
        class: MessageClass,
        transaction_id: TransactionId,
        error: MessageError,
    ) -> Self {
        InvalidMessage {
            method,
            class,
            transaction_id,
            error,
        }
    }
}

/// Response message.
pub type Response<A> = std::result::Result<SuccessResponse<A>, ErrorResponse<A>>;

/// Request message.
#[derive(Debug, Clone)]
pub struct Request<A>(Message<A>);
impl<A: Attribute> Request<A> {
    /// Makes a new request message.
    pub fn new(method: Method) -> Self {
        Request(Message::new(
            MessageClass::Request,
            method,
            TransactionId::new(rand::random()),
        ))
    }

    /// Converts `Message` to `Request`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::Request`,
    /// this function will return a `MessageErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `MessageErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::Request,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;
        Ok(Request(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns a reference to the first occurance of `T` attribute in the attributes of the message.
    ///
    /// If there is no such attribute, this method will return `None`.
    pub fn get_attribute<T>(&self) -> Option<&T>
    where
        T: Attribute,
        A: TryAsRef<T>,
    {
        self.0.get_attribute()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for Request<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for Request<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

/// Indication message.
#[derive(Debug, Clone)]
pub struct Indication<A>(Message<A>);
impl<A: Attribute> Indication<A> {
    /// Makes a new indication message.
    pub fn new(method: Method) -> Self {
        Indication(Message::new(
            MessageClass::Indication,
            method,
            TransactionId::new(rand::random()),
        ))
    }

    /// Converts `Message` to `Indication`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::Indication`,
    /// this function will return a `MessageErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `MessageErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::Indication,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;
        Ok(Indication(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns a reference to the first occurance of `T` attribute in the attributes of the message.
    ///
    /// If there is no such attribute, this method will return `None`.
    pub fn get_attribute<T>(&self) -> Option<&T>
    where
        T: Attribute,
        A: TryAsRef<T>,
    {
        self.0.get_attribute()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for Indication<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for Indication<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

/// Success response message.
#[derive(Debug, Clone)]
pub struct SuccessResponse<A>(Message<A>);
impl<A: Attribute> SuccessResponse<A> {
    /// Makes a new `SuccessResponse` instance for the success response to the given request.
    pub fn new(request: &Request<A>) -> Self {
        SuccessResponse(Message::new(
            MessageClass::SuccessResponse,
            request.method(),
            request.transaction_id(),
        ))
    }

    /// Converts `Message` to `SuccessResponse`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::SuccessResponse`,
    /// this function will return a `MessageErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `MessageErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::SuccessResponse,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;
        Ok(SuccessResponse(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns a reference to the first occurance of `T` attribute in the attributes of the message.
    ///
    /// If there is no such attribute, this method will return `None`.
    pub fn get_attribute<T>(&self) -> Option<&T>
    where
        T: Attribute,
        A: TryAsRef<T>,
    {
        self.0.get_attribute()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for SuccessResponse<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for SuccessResponse<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

/// Error response message.
#[derive(Debug, Clone)]
pub struct ErrorResponse<A>(Message<A>);
impl<A: Attribute> ErrorResponse<A> {
    /// Makes a new `ErrorResponse` instance for the error response to the given request.
    pub fn new(request: &Request<A>, error: ErrorCode) -> Self
    where
        A: From<ErrorCode>,
    {
        let mut message = Message::new(
            MessageClass::ErrorResponse,
            request.method(),
            request.transaction_id(),
        );
        message.add_attribute(error.into());
        ErrorResponse(message)
    }

    /// Converts `Message` to `ErrorResponse`.
    ///
    /// # Errors
    ///
    /// If the class of the given message is not `MessageClass::ErrorResponse` or
    /// the message does not contains an `ErrorCode` attribute,
    /// this function will return a `ErrorKind::InvalidInput` error.
    ///
    /// And if the message contains some unknown comprehension-required attributes,
    /// this function will return a `ErrorKind::UnknownAttributes` error.
    pub fn from_message(message: Message<A>) -> MessageResult<Self> {
        track_assert_eq!(
            message.class(),
            MessageClass::ErrorResponse,
            MessageErrorKind::InvalidInput
        );
        track!(check_unknown_attributes(&message))?;

        let contains_error_code = message
            .attributes()
            .map(|a| a.get_type())
            .chain(message.unknown_attributes().map(|a| a.get_type()))
            .any(|t| t.as_u16() == ErrorCode::CODEPOINT);
        track_assert!(contains_error_code, MessageErrorKind::InvalidInput);
        Ok(ErrorResponse(message))
    }

    /// Returns the method of the message.
    pub fn method(&self) -> Method {
        self.0.method()
    }

    /// Returns the transaction ID of the message.
    pub fn transaction_id(&self) -> TransactionId {
        self.0.transaction_id()
    }

    /// Returns a reference to the first occurance of `T` attribute in the attributes of the message.
    ///
    /// If there is no such attribute, this method will return `None`.
    pub fn get_attribute<T>(&self) -> Option<&T>
    where
        T: Attribute,
        A: TryAsRef<T>,
    {
        self.0.get_attribute()
    }

    /// Returns an iterator that iterates over the known attributes in the message.
    pub fn attributes(&self) -> impl Iterator<Item = &A> {
        self.0.attributes()
    }

    /// Adds the given attribute to the tail of the attributes in the message.
    pub fn add_attribute(&mut self, attribute: A) {
        self.0.add_attribute(attribute);
    }

    /// Takes ownership of this instance, and returns the internal message.
    pub fn into_message(self) -> Message<A> {
        self.0
    }
}
impl<A: Attribute> AsRef<Message<A>> for ErrorResponse<A> {
    fn as_ref(&self) -> &Message<A> {
        &self.0
    }
}
impl<A: Attribute> AsMut<Message<A>> for ErrorResponse<A> {
    fn as_mut(&mut self) -> &mut Message<A> {
        &mut self.0
    }
}

fn check_unknown_attributes<A: Attribute>(message: &Message<A>) -> MessageResult<()> {
    let required_unknowns = message
        .unknown_attributes()
        .filter_map(|a| {
            if a.get_type().is_comprehension_required() {
                Some(a.get_type())
            } else {
                None
            }
        }).collect::<Vec<_>>();
    track_assert!(
        required_unknowns.is_empty(),
        MessageErrorKind::UnknownAttributes(required_unknowns)
    );
    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::hash_map;
use std::slice::Iter;
use std::cmp::Ordering::Equal;

pub type Seconds = u8;

pub use self::Metric::*;

/// Metric collected from a collector to be recorded in a store.
#[derive(Clone, Debug, PartialEq)]
pub enum Metric {
    Count(String, u64),
    Measure(String, f64),
    Sample(String, f64),
}

#[derive(Debug, PartialEq)]
pub enum AggregatedMetricType {
    Count,
    Measure,
    Sample,
}

/// The final value resulting from aggregating a metric's values.
pub type AggregatedMetric = (AggregatedMetricType, String, f64);

/// All the metrics in a given time interval coalesced into a single value for
/// each metric.
#[derive(Debug, PartialEq)]
pub struct AggregatedMetrics {
    metrics: Vec<AggregatedMetric>,
}

impl AggregatedMetrics {
    pub fn new() -> AggregatedMetrics {
        AggregatedMetrics {
            metrics: vec![],
        }
    }

    pub fn with_metrics(metrics: Vec<AggregatedMetric>) -> AggregatedMetrics {
        AggregatedMetrics {
            metrics: metrics,
        }
    }

    pub fn aggregate_counts(&mut self, counts: hash_map::Iter<String, u64>) {
        for (name, value) in counts {
            self.metrics.push((AggregatedMetricType::Count, name.to_owned(), *value as f64))
        }
    }

    /// Rolls up all the given measures. The minimum, maximum, median,
    /// average (mean), and 95th percentile summary measures will all be
    /// emitted, as well as a total count of all the individual measures
    /// received in the period.
    pub fn aggregate_measures(&mut self, measures: hash_map::Iter<String, Vec<f64>>) {
        use self::AggregatedMetricType::*;

        for (name, values) in measures {
            let mut sorted = values.clone();
            sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));

            let min          = *sorted.first().unwrap();
            let max          = *sorted.last().unwrap();
            let median       = sorted[sorted.len() / 2]; // TODO: Improve how we calculate the median
            let average      = sorted.iter().fold(0.0, |sum, val| { sum + val }) / (sorted.len() as f64);
            let percentile95 = sorted[(sorted.len() as f64 * 0.95) as usize];

            self.metrics.push((Measure, format!("{}.min",          name), min));
            self.metrics.push((Measure, format!("{}.max",          name), max));
            self.metrics.push((Measure, format!("{}.median",       name), median));
            self.metrics.push((Measure, format!("{}.avg",          name), average));
            self.metrics.push((Measure, format!("{}.95percentile", name), percentile95));

            self.metrics.push((Count,   format!("{}.count", name), sorted.len() as f64));
        }
    }

    pub fn aggregate_samples(&mut self, samples: hash_map::Iter<String, f64>) {
        for (name, value) in samples {
            self.metrics.push((AggregatedMetricType::Sample, name.to_owned(), *value as f64))
        }
    }

    pub fn iter(&self) -> Iter<AggregatedMetric> {
        self.metrics.iter()
    }

    pub fn len(&self) -> usize {
        self.metrics.len()
    }
}
<commit_msg>Add computing of 99th percentile for measures<commit_after>use std::collections::hash_map;
use std::slice::Iter;
use std::cmp::Ordering::Equal;

pub type Seconds = u8;

pub use self::Metric::*;

/// Metric collected from a collector to be recorded in a store.
#[derive(Clone, Debug, PartialEq)]
pub enum Metric {
    Count(String, u64),
    Measure(String, f64),
    Sample(String, f64),
}

#[derive(Debug, PartialEq)]
pub enum AggregatedMetricType {
    Count,
    Measure,
    Sample,
}

/// The final value resulting from aggregating a metric's values.
pub type AggregatedMetric = (AggregatedMetricType, String, f64);

/// All the metrics in a given time interval coalesced into a single value for
/// each metric.
#[derive(Debug, PartialEq)]
pub struct AggregatedMetrics {
    metrics: Vec<AggregatedMetric>,
}

impl AggregatedMetrics {
    pub fn new() -> AggregatedMetrics {
        AggregatedMetrics {
            metrics: vec![],
        }
    }

    pub fn with_metrics(metrics: Vec<AggregatedMetric>) -> AggregatedMetrics {
        AggregatedMetrics {
            metrics: metrics,
        }
    }

    pub fn aggregate_counts(&mut self, counts: hash_map::Iter<String, u64>) {
        for (name, value) in counts {
            self.metrics.push((AggregatedMetricType::Count, name.to_owned(), *value as f64))
        }
    }

    /// Rolls up all the given measures. The minimum, maximum, median,
    /// average (mean), and 95th percentile summary measures will all be
    /// emitted, as well as a total count of all the individual measures
    /// received in the period.
    pub fn aggregate_measures(&mut self, measures: hash_map::Iter<String, Vec<f64>>) {
        use self::AggregatedMetricType::*;

        for (name, values) in measures {
            let mut sorted = values.clone();
            sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Equal));

            let min          = *sorted.first().unwrap();
            let max          = *sorted.last().unwrap();
            let median       = sorted[sorted.len() / 2]; // TODO: Improve how we calculate the median
            let average      = sorted.iter().fold(0.0, |sum, val| { sum + val }) / (sorted.len() as f64);
            let percentile95 = sorted[(sorted.len() as f64 * 0.95) as usize];
            let percentile99 = sorted[(sorted.len() as f64 * 0.99) as usize];

            self.metrics.push((Measure, format!("{}.min",          name), min));
            self.metrics.push((Measure, format!("{}.max",          name), max));
            self.metrics.push((Measure, format!("{}.median",       name), median));
            self.metrics.push((Measure, format!("{}.avg",          name), average));
            self.metrics.push((Measure, format!("{}.95percentile", name), percentile95));
            self.metrics.push((Measure, format!("{}.99percentile", name), percentile99));

            self.metrics.push((Count,   format!("{}.count", name), sorted.len() as f64));
        }
    }

    pub fn aggregate_samples(&mut self, samples: hash_map::Iter<String, f64>) {
        for (name, value) in samples {
            self.metrics.push((AggregatedMetricType::Sample, name.to_owned(), *value as f64))
        }
    }

    pub fn iter(&self) -> Iter<AggregatedMetric> {
        self.metrics.iter()
    }

    pub fn len(&self) -> usize {
        self.metrics.len()
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::io;
use std::fs;
use regex;
use regex::Regex;
use error::Error;

#[derive(Eq, PartialEq, Debug)]
pub struct Motion {
  pub name: String,
  pub add_path: PathBuf,
  pub sub_path: PathBuf,
}

impl fmt::Display for Motion {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let parent_display = format!("{}", self.add_path.parent().unwrap().display());
    try!(write!(f, "{}", parent_display));
    if parent_display != "" { try!(write!(f, "/")); }
    try!(write!(f, "{}", self.name));
    Ok(())
  }
}

#[derive(Eq, PartialEq, Debug)]
struct Template {
  extension: String,
  add_path: PathBuf,
  sub_path: PathBuf,
}

pub fn find(dir: &Path) -> Result<Vec<Motion>, Error> {
  let template = try!(find_template(dir));
  let motions = try!(find_motions(&template, dir));
  Ok(motions)
}

fn find_template(dir: &Path) -> Result<Template, Error> {
  let paths = try!(find_paths(dir.to_path_buf(), 1));

  // Create the regexi which will match our template file names.
  let add_re = Regex::new(r"^template\.add($|\..+$)").unwrap();
  let sub_re = Regex::new(r"^template\.sub($|\..+$)").unwrap();

  // Find our add and sub paths in our list of paths. Error if we can’t find
  // anything.
  let add_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| add_re.is_match(s)).unwrap_or(false))
    .ok_or(error!("Add template file was not found for directory '{}'.", dir.display()))
  );

  let sub_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| sub_re.is_match(s)).unwrap_or(false))
    .ok_or(error!("Sub template file was not found for directory '{}'.", dir.display()))
  );

  // Get both the add extension and the sub extension. We can safely unwrap the
  // file names because part of being an `add_path` or `sub_path` means we
  // already checked that a file name exists.
  let add_ext = add_re.replace_all(add_path.file_name().unwrap().to_str().unwrap(), "$1");
  let sub_ext = sub_re.replace_all(sub_path.file_name().unwrap().to_str().unwrap(), "$1");

  // If the extensions are not equal, there is an error.
  if add_ext != sub_ext {
    return Err(error!("Template extensions for add ('{}') and sub ('{}') do not match.", add_ext, sub_ext))
  }

  // Return our template.
  Ok(Template {
    extension: add_ext,
    add_path: add_path.to_path_buf(),
    sub_path: sub_path.to_path_buf(),
  })
}

fn find_motions(template: &Template, dir: &Path) -> Result<Vec<Motion>, Error> {
  // Get all the file names for our paths for later use. We also make sure we
  // return a tuple. This way we can keep the original path.
  let paths = try!(find_paths(dir.to_path_buf(), 100));
  let paths: Vec<(&PathBuf, &str)> = {
    paths
    .iter()
    .filter_map(|path| path.file_name().and_then(OsStr::to_str).map(|file_name| (path, file_name)))
    .collect()
  };

  // Create the filename regexi for add and sub using the template extension.
  let add_re = Regex::new(&(r"^(\d{6}-.+)\.add".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  let sub_re = Regex::new(&(r"^(\d{6}-.+)\.sub".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  // Construct a motions accumulator.
  let mut motions: Vec<Motion> = Vec::new();

  // Iterate through all of our paths…
  for &(ref add_path, add_file_name) in paths.iter() {
    // If this path is an add file continue…
    if add_re.is_match(add_file_name) {
      // Get the name and timestamp for this motion.
      let name = add_re.replace_all(add_file_name, "$1");
      // Get the sub path with a name that matches our add path. If it does not
      // exist, throw an error.
      let &(ref sub_path, _) = try!(
        paths
        .iter()
        .find(|&&(_, sub_file_name)| sub_re.is_match(sub_file_name) && sub_re.replace_all(sub_file_name, "$1") == name)
        .ok_or(error!("Sub file not found for add file '{}'.", add_path.display()))
      );
      // Add the motion to our accumulator.
      motions.push(Motion {
        name: name,
        add_path: add_path.to_path_buf(),
        sub_path: sub_path.to_path_buf(),
      });
    }
  }

  // Sort our motions by *file* name.
  motions.sort_by(|a, b| a.name.cmp(&b.name));

  // Return all of our motions.
  Ok(motions)
}

fn find_paths(path: PathBuf, recurse: u8) -> io::Result<Vec<PathBuf>> {
  // If the path is a directory let’s recursively go through every entry and
  // rerun our `discover_all` function.
  if try!(fs::metadata(&path)).is_dir() {
    // If we have ended our recursion, just return an empty vec.
    if recurse == 0 {
      return Ok(vec![])
    }
    // Create a new paths vec.
    let mut paths: Vec<PathBuf> = Vec::new();
    // Loop through the directory…
    for entry in try!(fs::read_dir(&path)) {
      // Get all the paths from this entry path by recursively calling the
      // function.
      let mut next_paths = try!(find_paths(try!(entry).path(), recurse - 1));
      // Append these next paths to our top level motions vec.
      paths.append(&mut next_paths);
    }
    // Return all of our motions.
    Ok(paths)
  }
  // Otherwise our path is not a directory and we should return a singleton
  // vector of the path.
  else {
    Ok(vec![path])
  }
}

#[cfg(test)]
mod tests {
  use std::path::{Path, PathBuf};
  use super::{find_paths, find, Motion, find_template, Template};

  fn pb(path: &str) -> PathBuf {
    Path::new(path).to_path_buf()
  }

  #[test]
  fn test_find_paths() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 100).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/b/c/456789-qux.add"),
      pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_find_paths_limit_recurse_1() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 1).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_find_paths_limit_recurse_2() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 2).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_fixtures_basic() {
    assert_eq!(find(Path::new("tests/fixtures/basic")).unwrap(), vec![
      Motion {
        name: "123456-foo".to_string(),
        add_path: pb("tests/fixtures/basic/123456-foo.add"),
        sub_path: pb("tests/fixtures/basic/123456-foo.sub"),
      },
      Motion {
        name: "234567-bar".to_string(),
        add_path: pb("tests/fixtures/basic/234567-bar.add"),
        sub_path: pb("tests/fixtures/basic/234567-bar.sub"),
      },
    ]);
  }

  #[test]
  fn test_template_basic() {
    assert_eq!(find_template(Path::new("tests/fixtures/basic")).unwrap(), Template {
      extension: "".to_string(),
      add_path: pb("tests/fixtures/basic/template.add"),
      sub_path: pb("tests/fixtures/basic/template.sub"),
    });
  }

  #[test]
  fn test_fixtures_nested() {
    assert_eq!(find(Path::new("tests/fixtures/nested")).unwrap(), vec![
      Motion {
        name: "123456-foo".to_string(),
        add_path: pb("tests/fixtures/nested/b/123456-foo.add"),
        sub_path: pb("tests/fixtures/nested/b/123456-foo.sub"),
      },
      Motion {
        name: "234567-bar".to_string(),
        add_path: pb("tests/fixtures/nested/234567-bar.add"),
        sub_path: pb("tests/fixtures/nested/234567-bar.sub"),
      },
      Motion {
        name: "345678-baz".to_string(),
        add_path: pb("tests/fixtures/nested/a/345678-baz.add"),
        sub_path: pb("tests/fixtures/nested/a/345678-baz.sub"),
      },
      Motion {
        name: "456789-qux".to_string(),
        add_path: pb("tests/fixtures/nested/b/c/456789-qux.add"),
        sub_path: pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      },
    ]);
  }

  #[test]
  fn test_template_nested() {
    assert_eq!(find_template(Path::new("tests/fixtures/nested")).unwrap(), Template {
      extension: "".to_string(),
      add_path: pb("tests/fixtures/nested/template.add"),
      sub_path: pb("tests/fixtures/nested/template.sub"),
    });
  }

  #[test]
  fn test_fixtures_extension() {
    assert_eq!(find(Path::new("tests/fixtures/extension")).unwrap(), vec![
      Motion {
        name: "123456-foo".to_string(),
        add_path: pb("tests/fixtures/extension/123456-foo.add.sql"),
        sub_path: pb("tests/fixtures/extension/123456-foo.sub.sql"),
      },
      Motion {
        name: "234567-bar".to_string(),
        add_path: pb("tests/fixtures/extension/234567-bar.add.sql"),
        sub_path: pb("tests/fixtures/extension/234567-bar.sub.sql"),
      },
    ]);
  }

  #[test]
  fn test_template_extension() {
    assert_eq!(find_template(Path::new("tests/fixtures/extension")).unwrap(), Template {
      extension: ".sql".to_string(),
      add_path: pb("tests/fixtures/extension/template.add.sql"),
      sub_path: pb("tests/fixtures/extension/template.sub.sql"),
    });
  }

  #[test]
  fn test_fixtures_bad_templateless() {
    assert!(find(Path::new("tests/fixtures/bad/templateless")).is_err());
  }

  #[test]
  fn test_bad_names() {
    assert!(find(Path::new("tests/fixtures/bad/names")).is_err());
  }

  #[test]
  fn test_motion_display_current_dir() {
    assert_eq!(format!("{}", Motion {
      name: "foo".to_string(),
      add_path: pb("foo.add"),
      sub_path: pb("foo.sub"),
    }), "foo");
  }

  #[test]
  fn test_motion_display_nested_dir() {
    assert_eq!(format!("{}", Motion {
      name: "foo".to_string(),
      add_path: pb("hello/world/foo.add"),
      sub_path: pb("hello/world/foo.sub"),
    }), "hello/world/foo");
  }

  #[test]
  fn test_motion_display_extension() {
    assert_eq!(format!("{}", Motion {
      name: "foo".to_string(),
      add_path: pb("foo.add.txt"),
      sub_path: pb("foo.sub.txt"),
    }), "foo");
  }
}
<commit_msg>loosen motion identification specification<commit_after>use std::fmt;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use std::io;
use std::fs;
use regex;
use regex::Regex;
use error::Error;

#[derive(Eq, PartialEq, Debug)]
pub struct Motion {
  pub name: String,
  pub add_path: PathBuf,
  pub sub_path: PathBuf,
}

impl fmt::Display for Motion {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    let parent_display = format!("{}", self.add_path.parent().unwrap().display());
    try!(write!(f, "{}", parent_display));
    if parent_display != "" { try!(write!(f, "/")); }
    try!(write!(f, "{}", self.name));
    Ok(())
  }
}

#[derive(Eq, PartialEq, Debug)]
struct Template {
  extension: String,
  add_path: PathBuf,
  sub_path: PathBuf,
}

pub fn find(dir: &Path) -> Result<Vec<Motion>, Error> {
  let template = try!(find_template(dir));
  let motions = try!(find_motions(&template, dir));
  Ok(motions)
}

fn find_template(dir: &Path) -> Result<Template, Error> {
  let paths = try!(find_paths(dir.to_path_buf(), 1));

  // Create the regexi which will match our template file names.
  let add_re = Regex::new(r"^template\.add($|\..+$)").unwrap();
  let sub_re = Regex::new(r"^template\.sub($|\..+$)").unwrap();

  // Find our add and sub paths in our list of paths. Error if we can’t find
  // anything.
  let add_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| add_re.is_match(s)).unwrap_or(false))
    .ok_or(error!("Add template file was not found for directory '{}'.", dir.display()))
  );

  let sub_path = try!(
    paths.iter()
    .find(|path| path.file_name().and_then(OsStr::to_str).map(|s| sub_re.is_match(s)).unwrap_or(false))
    .ok_or(error!("Sub template file was not found for directory '{}'.", dir.display()))
  );

  // Get both the add extension and the sub extension. We can safely unwrap the
  // file names because part of being an `add_path` or `sub_path` means we
  // already checked that a file name exists.
  let add_ext = add_re.replace_all(add_path.file_name().unwrap().to_str().unwrap(), "$1");
  let sub_ext = sub_re.replace_all(sub_path.file_name().unwrap().to_str().unwrap(), "$1");

  // If the extensions are not equal, there is an error.
  if add_ext != sub_ext {
    return Err(error!("Template extensions for add ('{}') and sub ('{}') do not match.", add_ext, sub_ext))
  }

  // Return our template.
  Ok(Template {
    extension: add_ext,
    add_path: add_path.to_path_buf(),
    sub_path: sub_path.to_path_buf(),
  })
}

fn find_motions(template: &Template, dir: &Path) -> Result<Vec<Motion>, Error> {
  // Get all the file names for our paths for later use. We also make sure we
  // return a tuple. This way we can keep the original path.
  let paths = try!(find_paths(dir.to_path_buf(), 100));
  let paths: Vec<(&PathBuf, &str)> = {
    paths
    .iter()
    .filter_map(|path| path.file_name().and_then(OsStr::to_str).map(|file_name| (path, file_name)))
    .collect()
  };

  // Create the filename regexi for add and sub using the template extension.
  let add_re = Regex::new(&(r"^(.+)\.add".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  let sub_re = Regex::new(&(r"^(.+)\.sub".to_owned() + &regex::quote(&template.extension) + "$")).unwrap();
  // Construct a motions accumulator.
  let mut motions: Vec<Motion> = Vec::new();

  // Iterate through all of our paths…
  for &(ref add_path, add_file_name) in paths.iter() {
    // If this path is an add file continue…
    if add_re.is_match(add_file_name) {
      // Get the name and timestamp for this motion.
      let name = add_re.replace_all(add_file_name, "$1");
      // Skip this file if it’s name is `add_file_name`.
      if name == "template" { continue; }
      // Get the sub path with a name that matches our add path. If it does not
      // exist, throw an error.
      let &(ref sub_path, _) = try!(
        paths
        .iter()
        .find(|&&(_, sub_file_name)| sub_re.is_match(sub_file_name) && sub_re.replace_all(sub_file_name, "$1") == name)
        .ok_or(error!("Sub file not found for add file '{}'.", add_path.display()))
      );
      // Add the motion to our accumulator.
      motions.push(Motion {
        name: name,
        add_path: add_path.to_path_buf(),
        sub_path: sub_path.to_path_buf(),
      });
    }
  }

  // Sort our motions by *file* name.
  motions.sort_by(|a, b| a.name.cmp(&b.name));

  // Return all of our motions.
  Ok(motions)
}

fn find_paths(path: PathBuf, recurse: u8) -> io::Result<Vec<PathBuf>> {
  // If the path is a directory let’s recursively go through every entry and
  // rerun our `discover_all` function.
  if try!(fs::metadata(&path)).is_dir() {
    // If we have ended our recursion, just return an empty vec.
    if recurse == 0 {
      return Ok(vec![])
    }
    // Create a new paths vec.
    let mut paths: Vec<PathBuf> = Vec::new();
    // Loop through the directory…
    for entry in try!(fs::read_dir(&path)) {
      // Get all the paths from this entry path by recursively calling the
      // function.
      let mut next_paths = try!(find_paths(try!(entry).path(), recurse - 1));
      // Append these next paths to our top level motions vec.
      paths.append(&mut next_paths);
    }
    // Return all of our motions.
    Ok(paths)
  }
  // Otherwise our path is not a directory and we should return a singleton
  // vector of the path.
  else {
    Ok(vec![path])
  }
}

#[cfg(test)]
mod tests {
  use std::path::{Path, PathBuf};
  use super::{find_paths, find, Motion, find_template, Template};

  fn pb(path: &str) -> PathBuf {
    Path::new(path).to_path_buf()
  }

  #[test]
  fn test_find_paths() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 100).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/b/c/456789-qux.add"),
      pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_find_paths_limit_recurse_1() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 1).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_find_paths_limit_recurse_2() {
    assert_eq!(find_paths(pb("tests/fixtures/nested"), 2).unwrap(), vec![
      pb("tests/fixtures/nested/234567-bar.add"),
      pb("tests/fixtures/nested/234567-bar.sub"),
      pb("tests/fixtures/nested/a/345678-baz.add"),
      pb("tests/fixtures/nested/a/345678-baz.sub"),
      pb("tests/fixtures/nested/b/123456-foo.add"),
      pb("tests/fixtures/nested/b/123456-foo.sub"),
      pb("tests/fixtures/nested/template.add"),
      pb("tests/fixtures/nested/template.sub"),
    ]);
  }

  #[test]
  fn test_fixtures_basic() {
    assert_eq!(find(Path::new("tests/fixtures/basic")).unwrap(), vec![
      Motion {
        name: "123456-foo".to_string(),
        add_path: pb("tests/fixtures/basic/123456-foo.add"),
        sub_path: pb("tests/fixtures/basic/123456-foo.sub"),
      },
      Motion {
        name: "234567-bar".to_string(),
        add_path: pb("tests/fixtures/basic/234567-bar.add"),
        sub_path: pb("tests/fixtures/basic/234567-bar.sub"),
      },
    ]);
  }

  #[test]
  fn test_template_basic() {
    assert_eq!(find_template(Path::new("tests/fixtures/basic")).unwrap(), Template {
      extension: "".to_string(),
      add_path: pb("tests/fixtures/basic/template.add"),
      sub_path: pb("tests/fixtures/basic/template.sub"),
    });
  }

  #[test]
  fn test_fixtures_nested() {
    assert_eq!(find(Path::new("tests/fixtures/nested")).unwrap(), vec![
      Motion {
        name: "123456-foo".to_string(),
        add_path: pb("tests/fixtures/nested/b/123456-foo.add"),
        sub_path: pb("tests/fixtures/nested/b/123456-foo.sub"),
      },
      Motion {
        name: "234567-bar".to_string(),
        add_path: pb("tests/fixtures/nested/234567-bar.add"),
        sub_path: pb("tests/fixtures/nested/234567-bar.sub"),
      },
      Motion {
        name: "345678-baz".to_string(),
        add_path: pb("tests/fixtures/nested/a/345678-baz.add"),
        sub_path: pb("tests/fixtures/nested/a/345678-baz.sub"),
      },
      Motion {
        name: "456789-qux".to_string(),
        add_path: pb("tests/fixtures/nested/b/c/456789-qux.add"),
        sub_path: pb("tests/fixtures/nested/b/c/456789-qux.sub"),
      },
    ]);
  }

  #[test]
  fn test_template_nested() {
    assert_eq!(find_template(Path::new("tests/fixtures/nested")).unwrap(), Template {
      extension: "".to_string(),
      add_path: pb("tests/fixtures/nested/template.add"),
      sub_path: pb("tests/fixtures/nested/template.sub"),
    });
  }

  #[test]
  fn test_fixtures_extension() {
    assert_eq!(find(Path::new("tests/fixtures/extension")).unwrap(), vec![
      Motion {
        name: "123456-foo".to_string(),
        add_path: pb("tests/fixtures/extension/123456-foo.add.sql"),
        sub_path: pb("tests/fixtures/extension/123456-foo.sub.sql"),
      },
      Motion {
        name: "234567-bar".to_string(),
        add_path: pb("tests/fixtures/extension/234567-bar.add.sql"),
        sub_path: pb("tests/fixtures/extension/234567-bar.sub.sql"),
      },
    ]);
  }

  #[test]
  fn test_template_extension() {
    assert_eq!(find_template(Path::new("tests/fixtures/extension")).unwrap(), Template {
      extension: ".sql".to_string(),
      add_path: pb("tests/fixtures/extension/template.add.sql"),
      sub_path: pb("tests/fixtures/extension/template.sub.sql"),
    });
  }

  #[test]
  fn test_fixtures_bad_templateless() {
    assert!(find(Path::new("tests/fixtures/bad/templateless")).is_err());
  }

  #[test]
  fn test_bad_names() {
    assert!(find(Path::new("tests/fixtures/bad/names")).is_err());
  }

  #[test]
  fn test_motion_display_current_dir() {
    assert_eq!(format!("{}", Motion {
      name: "foo".to_string(),
      add_path: pb("foo.add"),
      sub_path: pb("foo.sub"),
    }), "foo");
  }

  #[test]
  fn test_motion_display_nested_dir() {
    assert_eq!(format!("{}", Motion {
      name: "foo".to_string(),
      add_path: pb("hello/world/foo.add"),
      sub_path: pb("hello/world/foo.sub"),
    }), "hello/world/foo");
  }

  #[test]
  fn test_motion_display_extension() {
    assert_eq!(format!("{}", Motion {
      name: "foo".to_string(),
      add_path: pb("foo.add.txt"),
      sub_path: pb("foo.sub.txt"),
    }), "foo");
  }
}
<|endoftext|>


<commit_before>
use can::{
    CanTransform,
    CanViewTransform,
};
use has::{
    HasTransform,
    HasViewTransform,
};
use vecmath::{
    identity,
    get_scale,
    Scalar,
};

/// Should be implemented by contexts that
/// draws something relative to view.
pub trait View {
    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    fn view(&self) -> Self;

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    fn reset(&self) -> Self;

    /// Stores the current transform as new view.
    fn store_view(&self) -> Self;

    /// Computes the current view size.
    fn get_view_size(&self) -> (Scalar, Scalar);
}

impl<
    T: HasViewTransform
     + HasTransform
     + CanViewTransform
     + CanTransform
> View for T {
    #[inline(always)]
    fn view(&self) -> T {
        self.transform(self.get_view_transform())
    }

    #[inline(always)]
    fn reset(&self) -> T {
        self.transform(identity())
    }

    #[inline(always)]
    fn store_view(&self) -> T {
        self.view_transform(self.get_transform())
    }

    #[inline(always)]
    fn get_view_size(&self) -> (Scalar, Scalar) {
        let scale = get_scale(self.get_view_transform());
        (2.0 / scale[0], 2.0 / scale[1])
    }
}
<commit_msg>Moved `View` impl methods to trait<commit_after>
use can::{
    CanTransform,
    CanViewTransform,
};
use has::{
    HasTransform,
    HasViewTransform,
};
use vecmath::{
    identity,
    get_scale,
    Scalar,
};

/// Should be implemented by contexts that
/// draws something relative to view.
pub trait View:
    HasViewTransform + CanViewTransform
  + HasTransform + CanTransform
{
    /// Moves the current transform to the view coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the upper left corner
    /// with the x axis pointing to the right
    /// and the y axis pointing down.
    #[inline(always)]
    fn view(&self) -> Self {
        self.transform(self.get_view_transform())
    }

    /// Moves the current transform to the default coordinate system.
    ///
    /// This is usually [0.0, 0.0] in the center
    /// with the x axis pointing to the right
    /// and the y axis pointing up.
    #[inline(always)]
    fn reset(&self) -> Self {
        self.transform(identity())
    }

    /// Stores the current transform as new view.
    #[inline(always)]
    fn store_view(&self) -> Self {
        self.view_transform(self.get_transform())
    }

    /// Computes the current view size.
    #[inline(always)]
    fn get_view_size(&self) -> (Scalar, Scalar) {
        let scale = get_scale(self.get_view_transform());
        (2.0 / scale[0], 2.0 / scale[1])
    }
}

impl<
    T: HasViewTransform
     + HasTransform
     + CanViewTransform
     + CanTransform
> View for T {}

<|endoftext|>


<commit_before>use std::str::{from_utf8};
use std::ptr::null;
use std::ffi::{CString, CStr};
use std::io::Error as IoError;
use std::io::Result as IoResult;
use libc::{c_int, size_t, c_char, EINVAL};

#[repr(C)]
struct hostent {
    h_name: *const c_char,              /* official name of host */
    h_aliases: *const *const c_char,    /* alias list */
    h_addrtype: c_int,                  /* host address type */
    h_length: c_int,                    /* length of address */
    h_addr_list: *const *const c_char,  /* list of addresses */
}

extern {
    fn gethostname(name: *mut c_char, size: size_t) -> c_int;
    fn gethostbyname(name: *const c_char) -> *const hostent;
}

pub fn get_host_ip() -> IoResult<String> {
    let host = try!(get_host_name());
    let addr = try!(get_host_address(&host[..]));
    return Ok(addr);
}

pub fn get_host_name() -> IoResult<String> {
    let mut buf: Vec<u8> = Vec::with_capacity(256);
    let nbytes = unsafe {
        buf.set_len(256);
        gethostname(
            (&mut buf[..]).as_ptr() as *mut i8,
            256)
    };
    if nbytes != 0 {
        return Err(IoError::last_os_error());
    }
    return buf[..].splitn(2, |x| *x == 0u8)
           .next()
           .and_then(|x| String::from_utf8(x.to_vec()).ok())
           .ok_or(IoError::from_raw_os_error(EINVAL));
}

pub fn get_host_address(val: &str) -> IoResult<String> {
    let cval = CString::new(val).unwrap();
    unsafe {
        let hostent = gethostbyname(cval.as_ptr());
        if hostent == null() {
            return Err(IoError::last_os_error());
        }
        if (*hostent).h_length == 0 {
            return Err(IoError::from_raw_os_error(EINVAL));
        }
        return Ok(String::from_utf8(
            CStr::from_ptr(*(*hostent).h_addr_list).to_bytes().to_vec()
            ).unwrap());
    }
}
<commit_msg>Fix resolving hostname<commit_after>use std::str::{from_utf8};
use std::ptr::{null, copy};
use std::ffi::{CString};
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::net::Ipv4Addr;
use libc::{c_int, size_t, c_char, EINVAL};

#[repr(C)]
struct hostent {
    h_name: *const c_char,              /* official name of host */
    h_aliases: *const *const c_char,    /* alias list */
    h_addrtype: c_int,                  /* host address type */
    h_length: c_int,                    /* length of address */
    h_addr_list: *const *const c_char,  /* list of addresses */
}

extern {
    fn gethostname(name: *mut c_char, size: size_t) -> c_int;
    fn gethostbyname(name: *const c_char) -> *const hostent;
}

pub fn get_host_ip() -> IoResult<String> {
    let host = try!(get_host_name());
    let addr = try!(get_host_address(&host[..]));
    return Ok(addr);
}

pub fn get_host_name() -> IoResult<String> {
    let mut buf: Vec<u8> = Vec::with_capacity(256);
    let nbytes = unsafe {
        buf.set_len(256);
        gethostname(
            (&mut buf[..]).as_ptr() as *mut i8,
            256)
    };
    if nbytes != 0 {
        return Err(IoError::last_os_error());
    }
    return buf[..].splitn(2, |x| *x == 0u8)
           .next()
           .and_then(|x| String::from_utf8(x.to_vec()).ok())
           .ok_or(IoError::from_raw_os_error(EINVAL));
}

pub fn get_host_address(val: &str) -> IoResult<String> {
    let cval = CString::new(val).unwrap();
    unsafe {
        let hostent = gethostbyname(cval.as_ptr());
        if hostent == null() {
            return Err(IoError::last_os_error());
        }
        if (*hostent).h_length == 0 {
            return Err(IoError::from_raw_os_error(EINVAL));
        }
        let mut addr = [0u8; 4];
        copy(*(*hostent).h_addr_list, addr.as_mut_ptr() as *mut i8, 4);
        return Ok(format!("{}",
                  Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3])));
    }
}
<|endoftext|>