<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Boundary parsing for `multipart` requests.

use super::buf_redux::BufReader;
use super::{safemem, twoway};

use log::LogLevel;

use std::cmp;
use std::borrow::Borrow;

use std::io;
use std::io::prelude::*;

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    source: BufReader<R>,
    boundary: Vec<u8>,
    search_idx: usize,
    boundary_read: bool,
    at_end: bool,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        let mut boundary = boundary.into();
        safemem::prepend(b"--", &mut boundary);

        BoundaryReader {
            source: BufReader::new(reader),
            boundary: boundary,
            search_idx: 0,
            boundary_read: false,
            at_end: false,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        // Make sure there's enough bytes in the buffer to positively identify the boundary.
        let min_len = self.search_idx + (self.boundary.len() * 2);

        let buf = fill_buf_min(&mut self.source, min_len)?;

        if buf.is_empty() {
            debug!("fill_buf_min returned zero-sized buf");
            self.at_end = true;
            return Ok(buf);
        }

        if log_enabled!(LogLevel::Trace) {
            trace!("Buf: {:?}", String::from_utf8_lossy(buf));
        }

        debug!(
            "Before-loop Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        if !self.boundary_read && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            debug!("Find boundary loop! Lookahead len: {}", lookahead.len());

            // Look for the boundary, or if it isn't found, stop near the end.
            match twoway::find_bytes(lookahead, &self.boundary) {
                Some(found_idx) => {
                    self.search_idx += found_idx;
                    self.boundary_read = true;
                },
                None => {
                    self.search_idx += lookahead.len().saturating_sub(self.boundary.len() + 2);
                }
            }
        }

        debug!(
            "After-loop Buf len: {} Search idx: {} Boundary read: {:?}",
            buf.len(), self.search_idx, self.boundary_read
        );

        // If the two bytes before the boundary are a CR-LF, we need to back up
        // the cursor so we don't yield bytes that client code isn't expecting.
        if self.boundary_read && self.search_idx >= 2 {
            let two_bytes_before = &buf[self.search_idx - 2 .. self.search_idx];

            debug!("Two bytes before: {:?} ({:?}) (\"\\r\\n\": {:?})",
                   String::from_utf8_lossy(two_bytes_before), two_bytes_before, b"\r\n");

            if two_bytes_before == &*b"\r\n" {
                debug!("Subtract two!");
                self.search_idx -= 2;
            }
        }

        let ret_buf = &buf[..self.search_idx];

        if log_enabled!(LogLevel::Trace) {
            trace!("Returning buf: {:?}", String::from_utf8_lossy(ret_buf));
        }

        Ok(ret_buf)
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<bool> {
        if self.at_end {
            return Ok(true);
        }

        while !(self.boundary_read || self.at_end){
            debug!("Boundary not found yet");

            let buf_len = self.read_to_boundary()?.len();

            debug!("Discarding {} bytes", buf_len);

            if buf_len == 0 {
                break;
            }

            self.consume(buf_len);
        }

        self.source.consume(self.search_idx);
        self.search_idx = 0;

        if log_enabled!(LogLevel::Trace) {
            trace!("Consumed up to self.search_idx, remaining buf: {:?}",
                   String::from_utf8_lossy(self.source.get_buf()));
        }

        let consume_amt = {
            let buf = self.source.get_buf();
            self.boundary.len() + if buf.len() >=2 && buf[..2] == *b"\r\n" { 2 } else { 0 }
        };

        self.source.consume(consume_amt);
        self.boundary_read = false;

        let mut bytes_after = [0, 0];

        let read = self.source.read(&mut bytes_after)?;

        if read == 1 {
            let _ = self.source.read(&mut bytes_after[1..])?;
        }

        if bytes_after == *b"--" {
            self.at_end = true;
        } else if bytes_after != *b"\r\n" {
            warn!("Unexpected bytes following boundary: {:?}", String::from_utf8_lossy(&bytes_after));
        }

        if log_enabled!(LogLevel::Trace) {
            trace!("Consumed boundary (at_end: {:?}), remaining buf: {:?}",
                    self.at_end,
                   String::from_utf8_lossy(self.source.get_buf())
            );
        }

        Ok(self.at_end)
    }
}

impl<R> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.source.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let read = {
            let mut buf = self.read_to_boundary()?;
            // This shouldn't ever be an error so unwrapping is fine.
            buf.read(out).unwrap()
        };

        self.consume(read);
        Ok(read)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let true_amt = cmp::min(amt, self.search_idx);

        debug!("Consume! amt: {} true amt: {}", amt, true_amt);

        self.source.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

fn fill_buf_min<R: Read>(buf: &mut BufReader<R>, min: usize) -> io::Result<&[u8]> {
    const MAX_ATTEMPTS: usize = 3;

    let mut attempts = 0;

    while buf.available() < min && attempts < MAX_ATTEMPTS {
        if buf.read_into_buf()? == 0 { break; };
        attempts += 1;
    }

    Ok(buf.get_buf())
}

#[cfg(test)]
mod test {
    use super::BoundaryReader;

    use std::io;
    use std::io::prelude::*;

    const BOUNDARY: &'static str = "boundary";
    const TEST_VAL: &'static str = "--boundary\r
dashed-value-1\r
--boundary\r
dashed-value-2\r
--boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let reader = BoundaryReader::from_reader(src, BOUNDARY);

        test_boundary_reader(reader);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                src.read(dst).unwrap()
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        // Substitute for `.step_by()` being unstable.
        for split_at in 0 .. TEST_VAL.len(){
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(reader);
        }

    }

    fn test_boundary_reader<R: Read>(mut reader: BoundaryReader<R>) {
        let ref mut buf = String::new();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }
}
<commit_msg>Logging macros don't evaluate their arguments if the log level isn't enabled<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Boundary parsing for `multipart` requests.

use super::buf_redux::BufReader;
use super::{safemem, twoway};

use log::LogLevel;

use std::cmp;
use std::borrow::Borrow;

use std::io;
use std::io::prelude::*;

/// A struct implementing `Read` and `BufRead` that will yield bytes until it sees a given sequence.
#[derive(Debug)]
pub struct BoundaryReader<R> {
    source: BufReader<R>,
    boundary: Vec<u8>,
    search_idx: usize,
    boundary_read: bool,
    at_end: bool,
}

impl<R> BoundaryReader<R> where R: Read {
    #[doc(hidden)]
    pub fn from_reader<B: Into<Vec<u8>>>(reader: R, boundary: B) -> BoundaryReader<R> {
        let mut boundary = boundary.into();
        safemem::prepend(b"--", &mut boundary);

        BoundaryReader {
            source: BufReader::new(reader),
            boundary: boundary,
            search_idx: 0,
            boundary_read: false,
            at_end: false,
        }
    }

    fn read_to_boundary(&mut self) -> io::Result<&[u8]> {
        // Make sure there's enough bytes in the buffer to positively identify the boundary.
        let min_len = self.search_idx + (self.boundary.len() * 2);

        let buf = fill_buf_min(&mut self.source, min_len)?;

        if buf.is_empty() {
            debug!("fill_buf_min returned zero-sized buf");
            self.at_end = true;
            return Ok(buf);
        }

        trace!("Buf: {:?}", String::from_utf8_lossy(buf));

        debug!("Before-loop Buf len: {} Search idx: {} Boundary read: {:?}",
               buf.len(), self.search_idx, self.boundary_read);

        if !self.boundary_read && self.search_idx < buf.len() {
            let lookahead = &buf[self.search_idx..];

            debug!("Find boundary loop! Lookahead len: {}", lookahead.len());

            // Look for the boundary, or if it isn't found, stop near the end.
            match twoway::find_bytes(lookahead, &self.boundary) {
                Some(found_idx) => {
                    self.search_idx += found_idx;
                    self.boundary_read = true;
                },
                None => {
                    self.search_idx += lookahead.len().saturating_sub(self.boundary.len() + 2);
                }
            }
        }

        debug!("After-loop Buf len: {} Search idx: {} Boundary read: {:?}",
               buf.len(), self.search_idx, self.boundary_read);

        // If the two bytes before the boundary are a CR-LF, we need to back up
        // the cursor so we don't yield bytes that client code isn't expecting.
        if self.boundary_read && self.search_idx >= 2 {
            let two_bytes_before = &buf[self.search_idx - 2 .. self.search_idx];

            trace!("Two bytes before: {:?} ({:?}) (\"\\r\\n\": {:?})",
                   String::from_utf8_lossy(two_bytes_before), two_bytes_before, b"\r\n");

            if two_bytes_before == &*b"\r\n" {
                debug!("Subtract two!");
                self.search_idx -= 2;
            }
        }

        let ret_buf = &buf[..self.search_idx];

        trace!("Returning buf: {:?}", String::from_utf8_lossy(ret_buf));

        Ok(ret_buf)
    }

    #[doc(hidden)]
    pub fn consume_boundary(&mut self) -> io::Result<bool> {
        if self.at_end {
            return Ok(true);
        }

        while !(self.boundary_read || self.at_end){
            debug!("Boundary not found yet");

            let buf_len = self.read_to_boundary()?.len();

            debug!("Discarding {} bytes", buf_len);

            if buf_len == 0 {
                break;
            }

            self.consume(buf_len);
        }

        self.source.consume(self.search_idx);
        self.search_idx = 0;

        trace!("Consumed up to self.search_idx, remaining buf: {:?}",
               String::from_utf8_lossy(self.source.get_buf()));

        let consume_amt = {
            let buf = self.source.get_buf();
            self.boundary.len() + if buf.len() >=2 && buf[..2] == *b"\r\n" { 2 } else { 0 }
        };

        self.source.consume(consume_amt);
        self.boundary_read = false;

        let mut bytes_after = [0, 0];

        let read = self.source.read(&mut bytes_after)?;

        if read == 1 {
            let _ = self.source.read(&mut bytes_after[1..])?;
        }

        if bytes_after == *b"--" {
            self.at_end = true;
        } else if bytes_after != *b"\r\n" {
            debug!("Unexpected bytes following boundary: {:?}", String::from_utf8_lossy(&bytes_after));
        }

        trace!("Consumed boundary (at_end: {:?}), remaining buf: {:?}", self.at_end,
               String::from_utf8_lossy(self.source.get_buf()));

        Ok(self.at_end)
    }
}

impl<R> Borrow<R> for BoundaryReader<R> {
    fn borrow(&self) -> &R {
        self.source.get_ref()
    }
}

impl<R> Read for BoundaryReader<R> where R: Read {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        let read = {
            let mut buf = self.read_to_boundary()?;
            // This shouldn't ever be an error so unwrapping is fine.
            buf.read(out).unwrap()
        };

        self.consume(read);
        Ok(read)
    }
}

impl<R> BufRead for BoundaryReader<R> where R: Read {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        self.read_to_boundary()
    }

    fn consume(&mut self, amt: usize) {
        let true_amt = cmp::min(amt, self.search_idx);

        debug!("Consume! amt: {} true amt: {}", amt, true_amt);

        self.source.consume(true_amt);
        self.search_idx -= true_amt;
    }
}

fn fill_buf_min<R: Read>(buf: &mut BufReader<R>, min: usize) -> io::Result<&[u8]> {
    const MAX_ATTEMPTS: usize = 3;

    let mut attempts = 0;

    while buf.available() < min && attempts < MAX_ATTEMPTS {
        if buf.read_into_buf()? == 0 { break; };
        attempts += 1;
    }

    Ok(buf.get_buf())
}

#[cfg(test)]
mod test {
    use super::BoundaryReader;

    use std::io;
    use std::io::prelude::*;

    const BOUNDARY: &'static str = "boundary";
    const TEST_VAL: &'static str = "--boundary\r
dashed-value-1\r
--boundary\r
dashed-value-2\r
--boundary--";

    #[test]
    fn test_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (no split)");

        let src = &mut TEST_VAL.as_bytes();
        let reader = BoundaryReader::from_reader(src, BOUNDARY);

        test_boundary_reader(reader);
    }

    struct SplitReader<'a> {
        left: &'a [u8],
        right: &'a [u8],
    }

    impl<'a> SplitReader<'a> {
        fn split(data: &'a [u8], at: usize) -> SplitReader<'a> {
            let (left, right) = data.split_at(at);

            SplitReader {
                left: left,
                right: right,
            }
        }
    }

    impl<'a> Read for SplitReader<'a> {
        fn read(&mut self, dst: &mut [u8]) -> io::Result<usize> {
            fn copy_bytes_partial(src: &mut &[u8], dst: &mut [u8]) -> usize {
                src.read(dst).unwrap()
            }

            let mut copy_amt = copy_bytes_partial(&mut self.left, dst);

            if copy_amt == 0 {
                copy_amt = copy_bytes_partial(&mut self.right, dst)
            };

            Ok(copy_amt)
        }
    }

    #[test]
    fn test_split_boundary() {
        let _ = ::env_logger::init();
        debug!("Testing boundary (split)");

        // Substitute for `.step_by()` being unstable.
        for split_at in 0 .. TEST_VAL.len(){
            debug!("Testing split at: {}", split_at);

            let src = SplitReader::split(TEST_VAL.as_bytes(), split_at);
            let reader = BoundaryReader::from_reader(src, BOUNDARY);
            test_boundary_reader(reader);
        }

    }

    fn test_boundary_reader<R: Read>(mut reader: BoundaryReader<R>) {
        let ref mut buf = String::new();

        debug!("Read 1");
        let _ = reader.read_to_string(buf).unwrap();
        assert!(buf.is_empty(), "Buffer not empty: {:?}", buf);
        buf.clear();

        debug!("Consume 1");
        reader.consume_boundary().unwrap();

        debug!("Read 2");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-1");
        buf.clear();

        debug!("Consume 2");
        reader.consume_boundary().unwrap();

        debug!("Read 3");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "dashed-value-2");
        buf.clear();

        debug!("Consume 3");
        reader.consume_boundary().unwrap();

        debug!("Read 4");
        let _ = reader.read_to_string(buf).unwrap();
        assert_eq!(buf, "");
    }
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use serde_json;
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::types::RedisPool;
use ::sensors;
use ::modifiers;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".into(), "error".to_json());
        d.insert("reason".into(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}

impl ReadHandler {
    pub fn new(status: api::Status,
               redis_pool: RedisPool,
               sensor_specs: sensors::SafeSensorSpecs,
               status_modifiers: Vec<Box<modifiers::StatusModifier>>)
               -> ReadHandler {
        ReadHandler {
            status: status,
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
            status_modifiers: status_modifiers,
        }
    }

    fn build_response_json(&self) -> String {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {

            match sensor_spec.get_sensor_value(self.redis_pool.clone()) {

                // Value could be read successfullly
                Ok(value) => {
                    if status_copy.sensors.is_none() {
                        status_copy.sensors = Some(api::Sensors {
                            people_now_present: None,
                            temperature: None,
                        });
                    }
                    sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
                },

                // Value could not be read, do error logging
                Err(err) => {
                    warn!("Could not retrieve key '{}' from Redis, omiting the sensor", &sensor_spec.data_key);
                    match err {
                        sensors::SensorError::Redis(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::R2d2(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::UnknownSensor(e) => warn!("Error: {:?}", e),
                    }
                },
            }
        }

        for status_modifier in self.status_modifiers.iter() {
            status_modifier.modify(&mut status_copy);
        }

        // Serialize to JSON
        // TODO Using unwrap may be unsound here
        serde_json::to_string(&status_copy).unwrap()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl UpdateHandler {
    pub fn new(redis_pool: RedisPool, sensor_specs: sensors::SafeSensorSpecs)
               -> UpdateHandler {
        UpdateHandler {
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in Redis
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), sensors::SensorError> {
        // Validate sensor
        let sensor_specs = self.sensor_specs.lock().unwrap();
        let sensor_spec = try!(sensor_specs.iter()
                               .find(|&spec| spec.data_key == sensor)
                               .ok_or(sensors::SensorError::UnknownSensor(sensor.into())));

        // Store data
        sensor_spec.set_sensor_value(self.redis_pool.clone(), value)
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.into() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in Redis
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("Updating sensor value for sensor \"{}\" failed: {:?}", &sensor_name, e);
            let response = match e {
                sensors::SensorError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                sensors::SensorError::Redis(_) | sensors::SensorError::R2d2(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<commit_msg>Replace unwrap with expect<commit_after>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use serde_json;
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::types::RedisPool;
use ::sensors;
use ::modifiers;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".into(), "error".to_json());
        d.insert("reason".into(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
    status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}

impl ReadHandler {
    pub fn new(status: api::Status,
               redis_pool: RedisPool,
               sensor_specs: sensors::SafeSensorSpecs,
               status_modifiers: Vec<Box<modifiers::StatusModifier>>)
               -> ReadHandler {
        ReadHandler {
            status: status,
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
            status_modifiers: status_modifiers,
        }
    }

    fn build_response_json(&self) -> String {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {

            match sensor_spec.get_sensor_value(self.redis_pool.clone()) {

                // Value could be read successfullly
                Ok(value) => {
                    if status_copy.sensors.is_none() {
                        status_copy.sensors = Some(api::Sensors {
                            people_now_present: None,
                            temperature: None,
                        });
                    }
                    sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
                },

                // Value could not be read, do error logging
                Err(err) => {
                    warn!("Could not retrieve key '{}' from Redis, omiting the sensor", &sensor_spec.data_key);
                    match err {
                        sensors::SensorError::Redis(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::R2d2(e) => debug!("Error: {:?}", e),
                        sensors::SensorError::UnknownSensor(e) => warn!("Error: {:?}", e),
                    }
                },
            }
        }

        for status_modifier in self.status_modifiers.iter() {
            status_modifier.modify(&mut status_copy);
        }

        // Serialize to JSON
        serde_json::to_string(&status_copy)
            .expect("Status object could not be serialized to JSON. \
                     Please open an issue at https://github.com/coredump-ch/spaceapi-server-rs/issues")
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    redis_pool: RedisPool,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl UpdateHandler {
    pub fn new(redis_pool: RedisPool, sensor_specs: sensors::SafeSensorSpecs)
               -> UpdateHandler {
        UpdateHandler {
            redis_pool: redis_pool,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in Redis
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), sensors::SensorError> {
        // Validate sensor
        let sensor_specs = self.sensor_specs.lock().unwrap();
        let sensor_spec = try!(sensor_specs.iter()
                               .find(|&spec| spec.data_key == sensor)
                               .ok_or(sensors::SensorError::UnknownSensor(sensor.into())));

        // Store data
        sensor_spec.set_sensor_value(self.redis_pool.clone(), value)
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.into() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path()[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in Redis
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("Updating sensor value for sensor \"{}\" failed: {:?}", &sensor_name, e);
            let response = match e {
                sensors::SensorError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                sensors::SensorError::Redis(_) | sensors::SensorError::R2d2(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<|endoftext|>


<commit_before>use std::collections::VecDeque;

pub struct CircularBuffer<T> {
    buffer: VecDeque<T>,
    size: usize,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    EmptyBuffer,
    FullBuffer,
}

impl<T> CircularBuffer<T> {
    pub fn new(size: usize) -> Self {
        CircularBuffer {
            buffer: VecDeque::new(),
            size: size,
        }
    }

    pub fn read(&mut self) -> Result<T, Error> {
        self.buffer.pop_front().ok_or(Error::EmptyBuffer)
    }

    pub fn write(&mut self, v: T) -> Result<usize, Error> {
        if self.buffer.len() == self.size {
            return Err(Error::FullBuffer);
        }

        self.buffer.push_back(v);

        Ok(self.buffer.len())
    }

    pub fn overwrite(&mut self, v: T) {
        if self.buffer.len() == self.size {
            self.buffer.pop_front().unwrap();
        }

        self.buffer.push_back(v);
    }

    pub fn clear(&mut self) {
        self.buffer.clear()
    }
}
<commit_msg>Add code for the case when the size is 0<commit_after>use std::collections::VecDeque;

#[derive(Debug)]
pub struct CircularBuffer<T> {
    buffer: VecDeque<T>,
    size: usize,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    EmptyBuffer,
    FullBuffer,
}

impl<T> CircularBuffer<T> {
    pub fn new(size: usize) -> Self {
        CircularBuffer {
            buffer: VecDeque::new(),
            size: size,
        }
    }

    pub fn read(&mut self) -> Result<T, Error> {
        if self.size == 0 {
            return Err(Error::FullBuffer);
        }

        self.buffer.pop_front().ok_or(Error::EmptyBuffer)
    }

    pub fn write(&mut self, v: T) -> Result<usize, Error> {
        if self.size == 0 || self.buffer.len() == self.size {
            return Err(Error::FullBuffer);
        }

        self.buffer.push_back(v);

        Ok(self.buffer.len())
    }

    pub fn overwrite(&mut self, v: T) {
        if self.size == 0 {
            return;
        }

        if self.buffer.len() == self.size {
            self.buffer.pop_front().unwrap();
        }

        self.buffer.push_back(v);
    }

    pub fn clear(&mut self) {
        self.buffer.clear()
    }
}
<|endoftext|>


<commit_before>use common::eyre::{bail, Result};
use node_address::Address;
use node_dispatch::dispatch_block;
use stencila_schema::*;

use crate::{Pointable, Pointer, PointerMut, Visitor, VisitorMut};

impl Pointable for BlockContent {
    /// Resolve an [`Address`] into a node [`Pointer`].
    ///
    /// `BlockContent` is one of the pointer variants so return a `Pointer::Block` if
    /// the address is empty. Otherwise dispatch to variant.
    fn resolve(&self, address: &mut Address) -> Result<Pointer> {
        match address.is_empty() {
            true => Ok(Pointer::Block(self)),
            false => dispatch_block!(self, resolve, address),
        }
    }
    fn resolve_mut(&mut self, address: &mut Address) -> Result<PointerMut> {
        match address.is_empty() {
            true => Ok(PointerMut::Block(self)),
            false => dispatch_block!(self, resolve_mut, address),
        }
    }

    /// Find a node based on its `id` and return a [`Pointer`] to it.
    ///
    /// Dispatch to variant and if it returns `Pointer::Some` then rewrite to `Pointer::Block`
    fn find(&self, id: &str) -> Pointer {
        match dispatch_block!(self, find, id) {
            Pointer::Some => Pointer::Block(self),
            _ => Pointer::None,
        }
    }
    fn find_mut(&mut self, id: &str) -> PointerMut {
        match dispatch_block!(self, find_mut, id) {
            PointerMut::Some => PointerMut::Block(self),
            _ => PointerMut::None,
        }
    }

    /// Walk over a node with a [`Visitor`]
    ///
    /// `BlockContent` is one of the visited types so call `visit_block` and,
    /// if it returns `true`, continue walk over variant.
    fn walk(&self, address: Address, visitor: &mut impl Visitor) {
        let cont = visitor.visit_block(&address, self);
        if cont {
            dispatch_block!(self, walk, address, visitor)
        }
    }
    fn walk_mut(&mut self, address: Address, visitor: &mut impl VisitorMut) {
        let cont = visitor.visit_block_mut(&address, self);
        if cont {
            dispatch_block!(self, walk_mut, address, visitor)
        }
    }
}

// Implementations for `BlockContent` structs (usually only properties that are content or `Node`s)
// and associated enums (only variants containing content).

pointable_struct!(ClaimSimple, content);
pointable_struct!(CodeBlock);
pointable_struct!(CodeChunk, caption, errors);
pointable_variants!(CodeChunkCaption, CodeChunkCaption::VecBlockContent);
pointable_struct!(CodeError);
pointable_struct!(CollectionSimple);
pointable_struct!(FigureSimple, caption);
pointable_variants!(FigureCaption, FigureCaption::VecBlockContent);
pointable_struct!(Heading, content);
pointable_struct!(Include);
pointable_struct!(List, items);
pointable_struct!(ListItem, content);
pointable_variants!(
    ListItemContent,
    ListItemContent::VecBlockContent,
    ListItemContent::VecInlineContent
);
pointable_struct!(MathBlock);
pointable_struct!(Paragraph, content);
pointable_struct!(QuoteBlock, content);
pointable_struct!(TableCell, content);
pointable_struct!(TableRow, cells);
pointable_struct!(TableSimple, caption, rows);
pointable_variants!(TableCaption, TableCaption::VecBlockContent);
pointable_variants!(
    TableCellContent,
    TableCellContent::VecBlockContent,
    TableCellContent::VecInlineContent
);
pointable_struct!(ThematicBreak);
<commit_msg>chore(Node pointers): Add support for `Call`<commit_after>use common::eyre::{bail, Result};
use node_address::Address;
use node_dispatch::dispatch_block;
use stencila_schema::*;

use crate::{Pointable, Pointer, PointerMut, Visitor, VisitorMut};

impl Pointable for BlockContent {
    /// Resolve an [`Address`] into a node [`Pointer`].
    ///
    /// `BlockContent` is one of the pointer variants so return a `Pointer::Block` if
    /// the address is empty. Otherwise dispatch to variant.
    fn resolve(&self, address: &mut Address) -> Result<Pointer> {
        match address.is_empty() {
            true => Ok(Pointer::Block(self)),
            false => dispatch_block!(self, resolve, address),
        }
    }
    fn resolve_mut(&mut self, address: &mut Address) -> Result<PointerMut> {
        match address.is_empty() {
            true => Ok(PointerMut::Block(self)),
            false => dispatch_block!(self, resolve_mut, address),
        }
    }

    /// Find a node based on its `id` and return a [`Pointer`] to it.
    ///
    /// Dispatch to variant and if it returns `Pointer::Some` then rewrite to `Pointer::Block`
    fn find(&self, id: &str) -> Pointer {
        match dispatch_block!(self, find, id) {
            Pointer::Some => Pointer::Block(self),
            _ => Pointer::None,
        }
    }
    fn find_mut(&mut self, id: &str) -> PointerMut {
        match dispatch_block!(self, find_mut, id) {
            PointerMut::Some => PointerMut::Block(self),
            _ => PointerMut::None,
        }
    }

    /// Walk over a node with a [`Visitor`]
    ///
    /// `BlockContent` is one of the visited types so call `visit_block` and,
    /// if it returns `true`, continue walk over variant.
    fn walk(&self, address: Address, visitor: &mut impl Visitor) {
        let cont = visitor.visit_block(&address, self);
        if cont {
            dispatch_block!(self, walk, address, visitor)
        }
    }
    fn walk_mut(&mut self, address: Address, visitor: &mut impl VisitorMut) {
        let cont = visitor.visit_block_mut(&address, self);
        if cont {
            dispatch_block!(self, walk_mut, address, visitor)
        }
    }
}

// Implementations for `BlockContent` structs (usually only properties that are content or `Node`s)
// and associated enums (only variants containing content).

pointable_struct!(Call, arguments, content);

pointable_struct!(ClaimSimple, content);
pointable_struct!(CodeBlock);

pointable_struct!(CodeChunk, caption, errors);
pointable_variants!(CodeChunkCaption, CodeChunkCaption::VecBlockContent);
pointable_struct!(CodeError);

pointable_struct!(CollectionSimple);
pointable_struct!(FigureSimple, caption);
pointable_variants!(FigureCaption, FigureCaption::VecBlockContent);
pointable_struct!(Heading, content);
pointable_struct!(Include, content);

pointable_struct!(List, items);
pointable_struct!(ListItem, content);
pointable_variants!(
    ListItemContent,
    ListItemContent::VecBlockContent,
    ListItemContent::VecInlineContent
);

pointable_struct!(MathBlock);
pointable_struct!(Paragraph, content);
pointable_struct!(QuoteBlock, content);

pointable_struct!(TableCell, content);
pointable_struct!(TableRow, cells);
pointable_struct!(TableSimple, caption, rows);
pointable_variants!(TableCaption, TableCaption::VecBlockContent);
pointable_variants!(
    TableCellContent,
    TableCellContent::VecBlockContent,
    TableCellContent::VecInlineContent
);

pointable_struct!(ThematicBreak);
<|endoftext|>


<commit_before>use chrono::*;
use http_headers::*;
use hyper::header::Headers;
use openssl::crypto::hash::hash;
use openssl::crypto::hash::Type::SHA1;
use openssl::crypto::pkey::PKey;
use rustc_serialize::base64::ToBase64;
use std::fmt;
use std::fs::File;
use utils::{squeeze_path, expand_string};
use authentication::BASE64_AUTH;
use errors::*;

#[derive(Clone)]
pub struct Auth11 {
    body: Option<String>,
    date: String,
    headers: Headers,
    keypath: String,
    method: String,
    path: String,
    userid: String,
    version: String,
}

impl fmt::Debug for Auth11 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Auth11")
            .field("method", &self.method)
            .field("userid", &self.userid)
            .field("path", &self.path)
            .field("body", &self.body)
            .field("keypath", &self.keypath)
            .finish()
    }
}

impl Auth11 {
    pub fn new(path: &str, key: &str, method: &str, userid: &str, body: Option<String>) -> Auth11 {
        let dt = UTC::now().format("%Y-%m-%dT%H:%M:%SZ").to_string();

        let userid = userid.to_owned();
        let mut headers = Headers::new();
        headers.set(OpsSign(String::from("algorithm=sha1;version=1.1")));
        headers.set(OpsTimestamp(dt.clone()));
        headers.set(OpsUserId(userid.clone()));

        Auth11 {
            body: body,
            date: dt,
            headers: headers,
            keypath: key.to_owned(),
            method: method.to_owned(),
            path: squeeze_path(path.to_owned()),
            userid: userid,
            version: String::from("1.1"),
        }
    }

    fn hashed_path(&self) -> Result<String> {
        debug!("Path is: {:?}", &self.path);
        let hash = try!(hash(SHA1, &self.path.as_bytes())).to_base64(BASE64_AUTH);
        Ok(hash)
    }

    fn content_hash(&self) -> Result<String> {
        let body = expand_string(&self.body);
        let content = try!(hash(SHA1, body.as_bytes())).to_base64(BASE64_AUTH);
        debug!("{:?}", content);
        Ok(content)
    }

    fn set_content_hash(mut self) -> Result<Auth11> {
        let hsh = try!(self.content_hash());
        self.headers.set(OpsContentHash(hsh));
        Ok(self)
    }

    fn canonical_user_id(&self) -> Result<String> {
        hash(SHA1, &self.userid.as_bytes()).and_then(|res| Ok(res.to_base64(BASE64_AUTH)))
    }

    fn canonical_request(&self) -> Result<String> {
        let cr = format!("Method:{}\nHashed \
                          Path:{}\nX-Ops-Content-Hash:{}\nX-Ops-Timestamp:{}\nX-Ops-UserId:{}",
                          &self.method,
                          try!(self.hashed_path()),
                          try!(self.content_hash()),
                          self.date,
                          try!(self.canonical_user_id()));
        debug!("Canonical Request is: {:?}", cr);
        Ok(cr)
    }

    fn encrypted_request(&self) -> Result<String> {
        match File::open(&self.keypath) {
            Ok(mut fh) => {
                let key = PKey::private_key_from_pem(&mut fh).unwrap();
                let hash = try!(key.private_encrypt(&self.canonical_request().as_bytes()))
                    .to_base64(BASE64_AUTH);
                Ok(hash)
            }
            Err(_) => Err(ErrorKind::PrivateKeyError(self.keypath)),
        }
    }

    pub fn headers(self) -> Result<Headers> {
        let fin = self.set_content_hash();
        let enc = fin.encrypted_request();
        let mut headers = fin.headers;
        let mut i = 1;
        for h in enc.split('\n') {
            let key = format!("X-Ops-Authorization-{}", i);
            headers.set_raw(key, vec![h.as_bytes().to_vec()]);
            i += 1;
        }
        headers
    }
}

#[cfg(test)]
mod tests {
    use super::Auth11;

    use http_headers::*;
    use hyper::header::Headers;

    const PATH: &'static str = "/organizations/clownco";
    const BODY: &'static str = "Spec Body";
    const USER: &'static str = "spec-user";
    const DT: &'static str = "2009-01-01T12:00:00Z";

    const PRIVATE_KEY: &'static str = "fixtures/spec-user.pem";

    #[test]
    fn test_new_authentication() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, None);
        assert_eq!(auth.body, None)
    }

    #[test]
    fn test_userid() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, None);
        assert_eq!(auth.userid, "spec-user");
        assert_eq!(auth.headers.get::<OpsUserId>().unwrap().to_string(),
        "spec-user")
    }

    #[test]
    fn test_method() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, None);
        assert_eq!(auth.method, "GET")
    }

    #[test]
    fn test_canonical_user_id_v11() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, None);
        assert_eq!(auth.canonical_user_id(), "EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_canonical_request() {
        let auth = Auth11 {
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(""),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(auth.canonical_request(),
        "Method:POST\nHashed \
        Path:YtBWDn1blGGuFIuKksdwXzHU9oE=\nX-Ops-Content-Hash:\
                    DFteJZPVv6WKdQmMqZUQUumUyRs=\nX-Ops-Timestamp:2009-01-01T12:00:\
                    00Z\nX-Ops-UserId:EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_private_key() {
        let auth = Auth11 {
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(PRIVATE_KEY),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(&auth.encrypted_request(),
        "UfZD9dRz6rFu6LbP5Mo1oNHcWYxpNIcUfFCffJS1FQa0GtfU/vkt3/O5HuCM\n1wIFl/U0f5faH9EW\
        pXWY5NwKR031Myxcabw4t4ZLO69CIh/3qx1XnjcZvt2w\nc2R9bx/43IWA/r8w8Q6decuu0f6ZlNhe\
                    JeJhaYPI8piX/aH+uHBH8zTACZu8\nvMnl5MF3/OIlsZc8cemq6eKYstp8a8KYq9OmkB5IXIX6qVMJ\
                    HA6fRvQEB/7j\n281Q7oI/O+lE8AmVyBbwruPb7Mp6s4839eYiOdjbDwFjYtbS3XgAjrHlaD7W\nFD\
                    lbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A==")
    }

    #[test]
    fn test_headers() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, None);
        let headers = auth.headers();

        let _ = headers.get_raw("x-ops-authorization-1").unwrap();
    }
}
<commit_msg>fix auth 1.1<commit_after>use chrono::*;
use http_headers::*;
use hyper::header::Headers;
use openssl::hash::{MessageDigest, hash};
use openssl::rsa::Rsa;
use openssl::rsa::PKCS1_PADDING;
use rustc_serialize::base64::ToBase64;
use std::fmt;
use std::fs::File;
use std::io::Read;
use utils::{squeeze_path, expand_string};
use authentication::BASE64_AUTH;
use errors::*;

#[derive(Clone)]
pub struct Auth11 {
    api_version: String,
    body: Option<String>,
    date: String,
    pub headers: Headers,
    keypath: String,
    method: String,
    path: String,
    userid: String,
    version: String,
}

impl fmt::Debug for Auth11 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Auth11")
            .field("method", &self.method)
            .field("userid", &self.userid)
            .field("path", &self.path)
            .field("body", &self.body)
            .field("keypath", &self.keypath)
            .finish()
    }
}

impl Auth11 {
    pub fn new(path: &str,
               key: &str,
               method: &str,
               userid: &str,
               api_version: &str,
               body: Option<String>)
        -> Auth11 {
            let dt = UTC::now().format("%Y-%m-%dT%H:%M:%SZ").to_string();

            let userid: String = userid.into();

            let mut headers = Headers::new();
            headers.set(OpsSign(String::from("algorithm=sha1;version=1.1")));
            headers.set(OpsTimestamp(dt.clone()));
            headers.set(OpsUserId(userid.clone()));

            Auth11 {
                api_version: api_version.into(),
                body: body,
                date: dt,
                headers: headers,
                keypath: key.into(),
                method: method.into(),
                path: squeeze_path(path.into()),
                userid: userid,
                version: String::from("1.1"),
            }
        }

    fn hashed_path(&self) -> Result<String> {
        debug!("Path is: {:?}", &self.path);
        let hash = hash(MessageDigest::sha1(), &self.path.as_bytes())?.to_base64(BASE64_AUTH);
        Ok(hash)
    }

    fn content_hash(&self) -> Result<String> {
        let body = expand_string(&self.body);
        let content = hash(MessageDigest::sha1(), body.as_bytes())?.to_base64(BASE64_AUTH);
        debug!("{:?}", content);
        Ok(content)
    }

    fn set_content_hash(mut self) -> Result<Auth11> {
        let hsh = try!(self.content_hash());
        self.headers.set(OpsContentHash(hsh));
        Ok(self)
    }

    fn canonical_user_id(&self) -> Result<String> {
        hash(MessageDigest::sha1(), &self.userid.as_bytes())
            .and_then(|res| Ok(res.to_base64(BASE64_AUTH)))
            .map_err(|res| res.into())
    }

    fn canonical_request(&self) -> Result<String> {
        let cr = format!("Method:{}\nHashed Path:{}\n\
                          X-Ops-Content-Hash:{}\n\
                          X-Ops-Timestamp:{}\nX-Ops-UserId:{}",
                          &self.method,
                          try!(self.hashed_path()),
                          try!(self.content_hash()),
                          self.date,
                          try!(self.canonical_user_id()));
        debug!("Canonical Request is: {:?}", cr);
        Ok(cr)
    }

    fn encrypted_request(&self) -> Result<String> {
        let mut key: Vec<u8> = vec![];
        match File::open(&self.keypath) {
            Ok(mut fh) => {
                try!(fh.read_to_end(&mut key));
                let key = try!(Rsa::private_key_from_pem(key.as_slice()));

                let cr = try!(self.canonical_request());
                let cr = cr.as_bytes();

                let mut hash: Vec<u8> = vec![0; key.size()];
                try!(key.private_encrypt(cr, &mut hash, PKCS1_PADDING));
                Ok(hash.to_base64(BASE64_AUTH))
            }
            Err(_) => Err(ErrorKind::PrivateKeyError(self.keypath.clone()).into()),
        }
    }

    pub fn headers(self) -> Result<Headers> {
        let fin = try!(self.set_content_hash());
        let enc = try!(fin.encrypted_request());
        let mut headers = fin.headers;
        let mut i = 1;
        for h in enc.split('\n') {
            let key = format!("X-Ops-Authorization-{}", i);
            headers.set_raw(key, vec![h.as_bytes().to_vec()]);
            i += 1;
        }
        Ok(headers)
    }
}

#[cfg(test)]
mod tests {
    use super::Auth11;

    use http_headers::*;
    use hyper::header::Headers;

    const PATH: &'static str = "/organizations/clownco";
    const BODY: &'static str = "Spec Body";
    const USER: &'static str = "spec-user";
    const DT: &'static str = "2009-01-01T12:00:00Z";

    const PRIVATE_KEY: &'static str = "fixtures/spec-user.pem";

    #[test]
    fn test_new_authentication() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        assert_eq!(auth.body, None)
    }

    #[test]
    fn test_userid() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        assert_eq!(auth.userid, "spec-user");
        assert_eq!(auth.headers.get::<OpsUserId>().unwrap().to_string(),
        "spec-user")
    }

    #[test]
    fn test_method() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        assert_eq!(auth.method, "GET")
    }

    #[test]
    fn test_canonical_user_id_v11() {
        let auth = Auth11::new(PATH, PRIVATE_KEY, "GET", USER, "0", None);
        assert_eq!(auth.canonical_user_id().unwrap(), "EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_canonical_request() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(""),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(auth.canonical_request().unwrap(),
        "Method:POST\nHashed \
        Path:YtBWDn1blGGuFIuKksdwXzHU9oE=\nX-Ops-Content-Hash:\
                    DFteJZPVv6WKdQmMqZUQUumUyRs=\nX-Ops-Timestamp:2009-01-01T12:00:\
                    00Z\nX-Ops-UserId:EAF7Wv/hbAudWV5ZkwKz40Z/lO0=")
    }

    #[test]
    fn test_private_key() {
        let auth = Auth11 {
            api_version: String::from("1"),
            body: Some(String::from(BODY)),
            date: String::from(DT),
            headers: Headers::new(),
            keypath: String::from(PRIVATE_KEY),
            method: String::from("POST"),
            path: String::from(PATH),
            userid: String::from(USER),
            version: String::from("1.1"),
        };
        assert_eq!(&auth.encrypted_request().unwrap(),
        "UfZD9dRz6rFu6LbP5Mo1oNHcWYxpNIcUfFCffJS1FQa0GtfU/vkt3/O5HuCM\n1wIFl/U0f5faH9EW\
        pXWY5NwKR031Myxcabw4t4ZLO69CIh/3qx1XnjcZvt2w\nc2R9bx/43IWA/r8w8Q6decuu0f6ZlNhe\
                    JeJhaYPI8piX/aH+uHBH8zTACZu8\nvMnl5MF3/OIlsZc8cemq6eKYstp8a8KYq9OmkB5IXIX6qVMJ\
                    HA6fRvQEB/7j\n281Q7oI/O+lE8AmVyBbwruPb7Mp6s4839eYiOdjbDwFjYtbS3XgAjrHlaD7W\nFD\
                    lbAG7H8Dmvo+wBxmtNkszhzbBnEYtuwQqT8nM/8A==")
    }

    #[test]
    fn test_headers() {
        let auth = Auth11::new(PATH,
                               PRIVATE_KEY,
                               "GET",
                               USER,
                               "0",
                               None);
        let headers = auth.headers().unwrap();

        assert!(headers.get_raw("x-ops-authorization-1").is_some())
    }
}
<|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::cell::RefCell;
use std::collections::BTreeMap;
use std::iter::FromIterator;
use std::path::Path;
use std::rc::Rc;
use std::vec::Vec;

use engine::Cache;
use engine::Dev;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;
use engine::Filesystem;
use engine::Pool;

use super::blockdev::SimDev;
use super::cache::SimCacheDev;
use super::filesystem::SimFilesystem;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimPool {
    pub block_devs: Vec<Box<SimDev>>,
    pub cache_devs: Vec<Box<SimCacheDev>>,
    pub filesystems: BTreeMap<String, Box<SimFilesystem>>,
    pub raid_level: u16,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimPool {
    pub fn new_pool(rdm: Rc<RefCell<Randomizer>>,
                    blockdevs: &[Box<SimDev>],
                    raid_level: u16)
                    -> Box<Pool> {

        let mut vec = Vec::new();
        vec.extend_from_slice(blockdevs);
        let new_pool = SimPool {
            block_devs: vec,
            filesystems: BTreeMap::new(),
            cache_devs: Vec::new(),
            raid_level: raid_level,
            rdm: rdm,
        };

        Box::new(new_pool)
    }
}

impl Pool for SimPool {
    fn add_blockdev(&mut self, path: &Path) -> EngineResult<()> {
        self.block_devs.push(SimDev::new_dev(self.rdm.clone(), path));
        Ok(())
    }

    fn add_cachedev(&mut self, path: &Path) -> EngineResult<()> {
        self.cache_devs.push(SimCacheDev::new_cache(self.rdm.clone(), path));
        Ok(())
    }

    fn destroy_filesystem(&mut self, filesystem: &String) -> EngineResult<()> {
        match self.filesystems.remove(filesystem) {
            Some(_fs) => {
                return Ok(());
            }
            None => return Err(EngineError::Stratis(ErrorEnum::NotFound(String::from(filesystem.to_string())))),
        }
    }

    fn copy(&self) -> Box<Pool> {
        let pool_copy = SimPool {
            block_devs: self.block_devs.clone(),
            cache_devs: self.cache_devs.clone(),
            filesystems: self.filesystems.clone(),
            raid_level: self.raid_level.clone(),
            rdm: self.rdm.clone(),
        };
        Box::new(pool_copy)
    }

    fn create_filesystem(&mut self,
                         filesystem_name: &str,
                         mount_point: &str,
                         size: u64)
                         -> EngineResult<()> {

        if self.filesystems.contains_key(filesystem_name) {
            return Err(EngineError::Stratis(ErrorEnum::AlreadyExists(filesystem_name.into())));
        }

        self.filesystems.insert(filesystem_name.to_owned(),
                                SimFilesystem::new_filesystem(mount_point, size));
        Ok(())
    }

    fn list_filesystems(&self) -> EngineResult<BTreeMap<String, Box<Filesystem>>> {
        Ok(BTreeMap::from_iter(self.filesystems.iter().map(|x| (x.0.clone(), x.1.copy()))))
    }

    fn list_blockdevs(&self) -> EngineResult<Vec<Box<Dev>>> {
        Ok(Vec::from_iter(self.block_devs.iter().map(|x| (x.copy()))))
    }

    fn list_cachedevs(&self) -> EngineResult<Vec<Box<Cache>>> {
        Ok(Vec::from_iter(self.cache_devs.iter().map(|x| (x.copy()))))
    }
    fn remove_blockdev(&mut self, path: &Path) -> EngineResult<()> {
        let index = self.block_devs.iter().position(|x| x.has_same(path));
        match index {
            Some(index) => {
                self.block_devs.remove(index);
                return Ok(());
            }
            None => {
                return Err(EngineError::Stratis(ErrorEnum::NotFound(String::from(path.to_str()
                    .unwrap()))))
            }
        }
        Ok(())
    }

    fn remove_cachedev(&mut self, path: &Path) -> EngineResult<()> {
        let index = self.cache_devs.iter().position(|x| x.has_same(path));

        match index {
            Some(index) => {
                self.cache_devs.remove(index);
                return Ok(());
            }
            None => {
                return Err(EngineError::Stratis(ErrorEnum::NotFound(String::from(path.to_str()
                    .unwrap()))))
            }
        }
        Ok(())
    }
}
<commit_msg>Do not return a tuple of one element, just return the thing itself.<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::cell::RefCell;
use std::collections::BTreeMap;
use std::iter::FromIterator;
use std::path::Path;
use std::rc::Rc;
use std::vec::Vec;

use engine::Cache;
use engine::Dev;
use engine::EngineError;
use engine::EngineResult;
use engine::ErrorEnum;
use engine::Filesystem;
use engine::Pool;

use super::blockdev::SimDev;
use super::cache::SimCacheDev;
use super::filesystem::SimFilesystem;
use super::randomization::Randomizer;

#[derive(Debug)]
pub struct SimPool {
    pub block_devs: Vec<Box<SimDev>>,
    pub cache_devs: Vec<Box<SimCacheDev>>,
    pub filesystems: BTreeMap<String, Box<SimFilesystem>>,
    pub raid_level: u16,
    rdm: Rc<RefCell<Randomizer>>,
}

impl SimPool {
    pub fn new_pool(rdm: Rc<RefCell<Randomizer>>,
                    blockdevs: &[Box<SimDev>],
                    raid_level: u16)
                    -> Box<Pool> {

        let mut vec = Vec::new();
        vec.extend_from_slice(blockdevs);
        let new_pool = SimPool {
            block_devs: vec,
            filesystems: BTreeMap::new(),
            cache_devs: Vec::new(),
            raid_level: raid_level,
            rdm: rdm,
        };

        Box::new(new_pool)
    }
}

impl Pool for SimPool {
    fn add_blockdev(&mut self, path: &Path) -> EngineResult<()> {
        self.block_devs.push(SimDev::new_dev(self.rdm.clone(), path));
        Ok(())
    }

    fn add_cachedev(&mut self, path: &Path) -> EngineResult<()> {
        self.cache_devs.push(SimCacheDev::new_cache(self.rdm.clone(), path));
        Ok(())
    }

    fn destroy_filesystem(&mut self, filesystem: &String) -> EngineResult<()> {
        match self.filesystems.remove(filesystem) {
            Some(_fs) => {
                return Ok(());
            }
            None => return Err(EngineError::Stratis(ErrorEnum::NotFound(String::from(filesystem.to_string())))),
        }
    }

    fn copy(&self) -> Box<Pool> {
        let pool_copy = SimPool {
            block_devs: self.block_devs.clone(),
            cache_devs: self.cache_devs.clone(),
            filesystems: self.filesystems.clone(),
            raid_level: self.raid_level.clone(),
            rdm: self.rdm.clone(),
        };
        Box::new(pool_copy)
    }

    fn create_filesystem(&mut self,
                         filesystem_name: &str,
                         mount_point: &str,
                         size: u64)
                         -> EngineResult<()> {

        if self.filesystems.contains_key(filesystem_name) {
            return Err(EngineError::Stratis(ErrorEnum::AlreadyExists(filesystem_name.into())));
        }

        self.filesystems.insert(filesystem_name.to_owned(),
                                SimFilesystem::new_filesystem(mount_point, size));
        Ok(())
    }

    fn list_filesystems(&self) -> EngineResult<BTreeMap<String, Box<Filesystem>>> {
        Ok(BTreeMap::from_iter(self.filesystems.iter().map(|x| (x.0.clone(), x.1.copy()))))
    }

    fn list_blockdevs(&self) -> EngineResult<Vec<Box<Dev>>> {
        Ok(Vec::from_iter(self.block_devs.iter().map(|x| x.copy())))
    }

    fn list_cachedevs(&self) -> EngineResult<Vec<Box<Cache>>> {
        Ok(Vec::from_iter(self.cache_devs.iter().map(|x| x.copy())))
    }
    fn remove_blockdev(&mut self, path: &Path) -> EngineResult<()> {
        let index = self.block_devs.iter().position(|x| x.has_same(path));
        match index {
            Some(index) => {
                self.block_devs.remove(index);
                return Ok(());
            }
            None => {
                return Err(EngineError::Stratis(ErrorEnum::NotFound(String::from(path.to_str()
                    .unwrap()))))
            }
        }
        Ok(())
    }

    fn remove_cachedev(&mut self, path: &Path) -> EngineResult<()> {
        let index = self.cache_devs.iter().position(|x| x.has_same(path));

        match index {
            Some(index) => {
                self.cache_devs.remove(index);
                return Ok(());
            }
            None => {
                return Err(EngineError::Stratis(ErrorEnum::NotFound(String::from(path.to_str()
                    .unwrap()))))
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.storepath.clone() + owner.name() + "-" + &id[..] + ".imag"
    }

}

#[derive(Debug)]
pub struct StorageBackendError<'a> {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl<'a> StorageBackendError<'a> {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl<'a> Error for StorageBackendError<'a> {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError<'a> {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>Reimplement StorageBackend::put_file()<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = p.write(f.contents())
            .or_else(|err| {
                let mut serr = StorageBackendError::build(
                    "Parser::write()",
                    "Cannot parse file contents",
                    "Cannot translate internal representation of file contents into on-disk representation",
                    None
                );
                serr.caused_by = Some(&err);
                Err(serr)
            });

        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            "", None
                        );
                    err.caused_by = Some(&ioerr);
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                "", None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.storepath.clone() + owner.name() + "-" + &id[..] + ".imag"
    }

}

#[derive(Debug)]
pub struct StorageBackendError<'a> {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl<'a> StorageBackendError<'a> {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
           data  : Option<String>) -> StorageBackendError<'a>
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl<'a> Error for StorageBackendError<'a> {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError<'a> {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<|endoftext|>


<commit_before>mod trajectory;
use trajectory::*;
mod energy;
use energy::*;

const LJ_EPS : f64 = 1.0;
const LJ_SIG : f64 = 1.0;

fn get_virial(distance_sqr: f64) -> f64 {
    let r2 = LJ_SIG.powi(2)/distance_sqr;
    let r6 = r2 * r2 * r2;
    return 48.0 * LJ_EPS / LJ_SIG * ( r6*r6 - 0.5*r6 )
}

fn get_distance_with_pbc(x1: f64, x2: f64, length: f64, half_length: f64) -> f64 {
    let mut d = x1-x2;
    if d > half_length { d -= length }
    else if d < -half_length { d += length }
    return d;
}

fn main() {

    let mut trj_reader = TrjReader::new(&"2phases/1kk_100step.xyz".to_string());
    let mut frame = trj_reader.next_frame();

    let volume = frame.box_x * frame.box_y * frame.box_z;
    let density = frame.num_particles as f64 / volume;
    let num_particles = frame.num_particles;

    let box_half_x = frame.box_x / 2.0;
    let box_half_y = frame.box_y / 2.0;
    let box_half_z = frame.box_z / 2.0;

    let mut frame_count = 0;
    let mut p_xy_sum = 0.0;
//    let mut p_y_sum = 0.0;
    let mut p_z_sum = 0.0;

    let variable_without_name = frame.temperature/LJ_EPS * density;

    loop {
        frame_count += 1;

        let mut trace_xy = 0.0;
//        let mut trace_y = 0.0;
        let mut trace_z = 0.0;
        for i in 0..num_particles {
            for j in i+1..num_particles {
                let dist_sqrt = get_particle_distance_squared(frame.rx[i], frame.ry[i], frame.rz[i], frame.rx[j], frame.ry[j], frame.rz[j], frame.box_x, frame.box_y, frame.box_z, box_half_x, box_half_y, box_half_z);
                let dist = dist_sqrt.sqrt();
                let dx = get_distance_with_pbc(frame.rx[i], frame.rx[j], frame.box_x, box_half_x);
                let dy = get_distance_with_pbc(frame.ry[i], frame.ry[j], frame.box_y, box_half_y);
                let dz = get_distance_with_pbc(frame.rz[i], frame.rz[j], frame.box_z, box_half_z);
                let virial = get_virial(dist_sqrt);
                trace_xy += (dx * dx + dy * dy) / dist * virial;
//                trace_y += (dy * dy) / dist * virial;
                trace_z += (dz * dz) / dist * virial;
            }
        }
        let p_xy = variable_without_name - 1.0/(2.0*volume)*(trace_xy/num_particles as f64);
//        let p_yy = variable_without_name - 1.0/volume*(trace_y/num_particles);
        let p_zz = variable_without_name - 1.0/volume*(trace_z/num_particles as f64);

        p_xy_sum += p_xy;
//        p_y_sum += p_yy;
        p_z_sum += p_zz;

        ///////////////////////////////////

        if frame_count % 100 == 0 {
            print!(".");
        }

        if frame_count % 100 == 0 {
            let p_z_avg = p_z_sum / frame_count as f64;
            let p_xy_avg = p_xy_sum / frame_count as f64;
            let p_diff = p_z_avg - p_xy_avg;
            let surface_tension = (frame.box_z/2.0)*p_diff;
            println!("{}  zz: {}   xy: {}    diff: {}    tension:   {}", frame_count, p_z_avg, p_xy_avg, p_diff, surface_tension);

            frame_count = 0;
            p_z_sum = 0.0;
            p_xy_sum = 0.0;
//            trace_xy_sum = 0.0;
//            trace_z_sum = 0.0;
//            p_tangial_sum = 0.0;
//            p_normal_sum = 0.0

        }

        if !trj_reader.update_with_next(&mut frame) { break }
    }

}

//        for slab in 0..NUM_SLABS {
//
//            // calculate slab density
//            let slab_end_z = slab_height * slab as f64;
//            let slab_start_z = slab_end_z - slab_height;
//            let mut slab_particle_count = 0;
//            for i in 0..frame.num_particles {
//                if slab_start_z > frame.rz[i] && frame.rz[i] < slab_end_z {
//                    slab_particle_count += 1;
//                }
//            }
//            let slab_density = slab_particle_count as f64 / slab_volume;
//
//            for i in 0..frame.num_particles {
//                for j in i+1..frame.num_particles {
//
//                }
//            }
//
//            println!("Slab {}\tDensity: {}", slab, slab_density);
//        }<commit_msg>surface tension reimplemented as running average (and maybe correct values now)<commit_after>mod trajectory;
use trajectory::*;
mod energy;
use energy::*;
use std::env;

const LJ_EPS : f64 = 1.0;
const LJ_SIG : f64 = 1.0;

fn get_virial(distance: f64) -> f64 {
    let r7 = (LJ_SIG/distance).powi(7);
    let r13 = (LJ_SIG/distance).powi(13);
    return 24.0 * LJ_EPS / LJ_SIG * ( r7-2.0*r13 );
}

#[test]
fn test_get_viral() {
    let result = get_virial(2.5);
    let expected = 0.038999477;
    assert!( (result - expected) < 0.0001, "{}", result );
}

fn get_distance_with_pbc(x1: f64, x2: f64, length: f64, half_length: f64) -> f64 {
    let mut d = (x1-x2).abs();
    if d > half_length { d -= length }
    else if d < -half_length { d += length }
    return d;
}

fn eval_surface_tension(box_z: f64, p_zz: f64, p_xy: f64) -> f64 {
    return box_z / 2.0 * (p_zz - p_xy);
}

#[test]
fn test_eval_surface_tension() {
    let expected = 2.0;
    let result = eval_surface_tension(2.0,5.0,3.0);
    assert!( (result-expected).abs() < 0.0001, "{}", result );
}

fn main() {

    // parse args
    let args: Vec<String> = env::args().collect();
    let mut filename = "montecarlo.xyz".to_string();
    let mut skip: usize = 0;
    for i in 0..args.len() {
        if args[i] == "-f" {
            filename = args[i + 1].clone();
        } else if args[i] == "-s" {
            skip = args[i + 1].parse::<usize>().unwrap();
        }
    }

    // open file and skip to requiested position
    let mut trj_reader = TrjReader::new(&filename);
    if skip > 0 { trj_reader.skip(skip) };

    // trajectory information
    let mut frame = trj_reader.next_frame();
    println!("{:?}", frame);

    let volume = frame.box_x * frame.box_y * frame.box_z;
    let density = frame.num_particles as f64 / volume;
    let num_particles = frame.num_particles;

    let box_half_x = frame.box_x / 2.0;
    let box_half_y = frame.box_y / 2.0;
    let box_half_z = frame.box_z / 2.0;

    let mut frame_count = 0;
    let mut p_xy_sum = 0.0;
    let mut p_z_sum = 0.0;

    let variable_without_name = frame.temperature/LJ_EPS * density;

    println!("~~~ THIS IS A RUNNING AVERAGE! ~~~");
    loop {
        frame_count += 1;

        let mut trace_xy = 0.0;
        let mut trace_z = 0.0;
        for i in 0..num_particles {
            for j in i+1..num_particles {
                let dist_sqrt = get_particle_distance_squared(frame.rx[i], frame.ry[i], frame.rz[i], frame.rx[j], frame.ry[j], frame.rz[j], frame.box_x, frame.box_y, frame.box_z, box_half_x, box_half_y, box_half_z);
                let dist = dist_sqrt.sqrt();
                let dx = get_distance_with_pbc(frame.rx[i], frame.rx[j], frame.box_x, box_half_x);
                let dy = get_distance_with_pbc(frame.ry[i], frame.ry[j], frame.box_y, box_half_y);
                let dz = get_distance_with_pbc(frame.rz[i], frame.rz[j], frame.box_z, box_half_z);
                let virial = get_virial(dist);
                trace_xy += (dx * dx + dy * dy) / dist * virial;
                trace_z += (dz * dz) / dist * virial;
            }
        }
        let p_xy = variable_without_name - 1.0/(2.0*volume)*(trace_xy);
        let p_zz = variable_without_name - 1.0/volume*(trace_z);

        p_xy_sum += p_xy;
        p_z_sum += p_zz;

        ///////////////////////////////////
        if frame_count % 10 == 0 {
            let p_z_avg = p_z_sum / frame_count as f64;
            let p_xy_avg = p_xy_sum / frame_count as f64;
            let p_diff = p_z_avg - p_xy_avg;
            let surface_tension = eval_surface_tension(frame.box_z, p_z_avg, p_xy_avg);
            println!("Frame {}\t\tzz: {:.5}\txy: {:.5}\tdifference: {:.5}\t\ttension: {:.5}", frame_count, p_z_avg, p_xy_avg, p_diff, surface_tension);

            // frame_count = 0;
            // p_z_sum = 0.0;
            // p_xy_sum = 0.0;
        }

        if !trj_reader.update_with_next(&mut frame) { break }
    }

}
<|endoftext|>


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

// compile-flags: --crate-type dylib --target thumbv7em-none-eabihf
// compile-pass
// error-pattern: dropping unsupported crate type `dylib` for target `thumbv7em-none-eabihf`

#![feature(no_core)]

#![no_std]
#![no_core]<commit_msg>Update issue-50993.rs<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: --crate-type dylib --target thumbv7em-none-eabihf
// compile-pass
// error-pattern: dropping unsupported crate type `dylib` for target `thumbv7em-none-eabihf`

#![feature(no_core)]

#![no_std]
#![no_core]
<|endoftext|>