<commit_before>//! Raster implementation.

use ::{Raster,RasterMut};

impl<'a> Raster<'a> {
    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let buf = [0; SCREEN_W * SCREEN_H];
    /// let pal = [0; 3 * NUM_COLS];
    ///
    /// flic::Raster::new(SCREEN_W, SCREEN_H, &buf, &pal);
    /// ```
    pub fn new(w: usize, h: usize, buf: &'a [u8], pal: &'a [u8])
            -> Self {
        Self::with_offset(0, 0, w, h, w, buf, pal)
    }

    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices, with an offset and stride.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let buf = [0; SCREEN_W * SCREEN_H];
    /// let pal = [0; 3 * NUM_COLS];
    ///
    /// flic::Raster::with_offset(0, 0, SCREEN_W, SCREEN_H, SCREEN_W, &buf, &pal);
    /// ```
    pub fn with_offset(
            x: usize, y: usize, w: usize, h: usize, stride: usize,
            buf: &'a [u8], pal: &'a [u8])
            -> Self {
        let x1 = x.checked_add(w).expect("overflow");
        let y1 = y.checked_add(h).expect("overflow");
        assert!(x < x1 && x1 <= stride && h > 0);
        assert!(stride.checked_mul(y1).expect("overflow") <= buf.len());
        assert!(pal.len() == 3 * 256);

        Raster {
            x: x,
            y: y,
            w: w,
            h: h,
            stride: stride,
            buf: buf,
            pal: pal,
        }
    }
}

impl<'a> RasterMut<'a> {
    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let mut buf = [0; SCREEN_W * SCREEN_H];
    /// let mut pal = [0; 3 * NUM_COLS];
    ///
    /// flic::RasterMut::new(SCREEN_W, SCREEN_H, &mut buf, &mut pal);
    /// ```
    pub fn new(w: usize, h: usize, buf: &'a mut [u8], pal: &'a mut [u8])
            -> Self {
        Self::with_offset(0, 0, w, h, w, buf, pal)
    }

    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices, with an offset and stride.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let mut buf = [0; SCREEN_W * SCREEN_H];
    /// let mut pal = [0; 3 * NUM_COLS];
    ///
    /// flic::RasterMut::with_offset(0, 0, SCREEN_W, SCREEN_H, SCREEN_W, &mut buf, &mut pal);
    /// ```
    pub fn with_offset(
            x: usize, y: usize, w: usize, h: usize, stride: usize,
            buf: &'a mut [u8], pal: &'a mut [u8])
            -> Self {
        let x1 = x.checked_add(w).expect("overflow");
        let y1 = y.checked_add(h).expect("overflow");
        assert!(x < x1 && x1 <= stride && h > 0);
        assert!(stride.checked_mul(y1).expect("overflow") <= buf.len());
        assert!(pal.len() == 3 * 256);

        RasterMut {
            x: x,
            y: y,
            w: w,
            h: h,
            stride: stride,
            buf: buf,
            pal: pal,
        }
    }
}

#[cfg(test)]
mod tests {
    use ::{Raster,RasterMut};

    #[test]
    #[should_panic]
    fn test_raster_overflow() {
        let buf = [0; 1];
        let pal = [0; 3 * 256];
        let _ = Raster::new(
                ::std::usize::MAX, ::std::usize::MAX, &buf, &pal);
    }

    #[test]
    #[should_panic]
    fn test_raster_mut_overflow() {
        let mut buf = [0; 1];
        let mut pal = [0; 3 * 256];
        let _ = RasterMut::new(
                ::std::usize::MAX, ::std::usize::MAX, &mut buf, &mut pal);
    }
}
<commit_msg>Clean up.<commit_after>//! Raster implementation.

use ::{Raster,RasterMut};

impl<'a> Raster<'a> {
    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let buf = [0; SCREEN_W * SCREEN_H];
    /// let pal = [0; 3 * NUM_COLS];
    ///
    /// flic::Raster::new(SCREEN_W, SCREEN_H, &buf, &pal);
    /// ```
    pub fn new(w: usize, h: usize, buf: &'a [u8], pal: &'a [u8])
            -> Self {
        Self::with_offset(0, 0, w, h, w, buf, pal)
    }

    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices, with an offset and stride.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let buf = [0; SCREEN_W * SCREEN_H];
    /// let pal = [0; 3 * NUM_COLS];
    ///
    /// flic::Raster::with_offset(0, 0, SCREEN_W, SCREEN_H, SCREEN_W, &buf, &pal);
    /// ```
    pub fn with_offset(
            x: usize, y: usize, w: usize, h: usize, stride: usize,
            buf: &'a [u8], pal: &'a [u8])
            -> Self {
        let x1 = x.checked_add(w).expect("overflow");
        let y1 = y.checked_add(h).expect("overflow");
        assert!(x < x1 && x1 <= stride && h > 0);
        assert!(stride.checked_mul(y1).expect("overflow") <= buf.len());
        assert!(pal.len() == 3 * 256);

        Raster {
            x, y, w, h, stride, buf, pal,
        }
    }
}

impl<'a> RasterMut<'a> {
    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let mut buf = [0; SCREEN_W * SCREEN_H];
    /// let mut pal = [0; 3 * NUM_COLS];
    ///
    /// flic::RasterMut::new(SCREEN_W, SCREEN_H, &mut buf, &mut pal);
    /// ```
    pub fn new(w: usize, h: usize, buf: &'a mut [u8], pal: &'a mut [u8])
            -> Self {
        Self::with_offset(0, 0, w, h, w, buf, pal)
    }

    /// Allocate a new raster for the given screen buffer and palette
    /// memory slices, with an offset and stride.
    ///
    /// # Examples
    ///
    /// ```
    /// const SCREEN_W: usize = 320;
    /// const SCREEN_H: usize = 200;
    /// const NUM_COLS: usize = 256;
    /// let mut buf = [0; SCREEN_W * SCREEN_H];
    /// let mut pal = [0; 3 * NUM_COLS];
    ///
    /// flic::RasterMut::with_offset(0, 0, SCREEN_W, SCREEN_H, SCREEN_W, &mut buf, &mut pal);
    /// ```
    pub fn with_offset(
            x: usize, y: usize, w: usize, h: usize, stride: usize,
            buf: &'a mut [u8], pal: &'a mut [u8])
            -> Self {
        let x1 = x.checked_add(w).expect("overflow");
        let y1 = y.checked_add(h).expect("overflow");
        assert!(x < x1 && x1 <= stride && h > 0);
        assert!(stride.checked_mul(y1).expect("overflow") <= buf.len());
        assert!(pal.len() == 3 * 256);

        RasterMut {
            x, y, w, h, stride, buf, pal,
        }
    }
}

#[cfg(test)]
mod tests {
    use ::{Raster,RasterMut};

    #[test]
    #[should_panic]
    fn test_raster_overflow() {
        let buf = [0; 1];
        let pal = [0; 3 * 256];
        let _ = Raster::new(
                ::std::usize::MAX, ::std::usize::MAX, &buf, &pal);
    }

    #[test]
    #[should_panic]
    fn test_raster_mut_overflow() {
        let mut buf = [0; 1];
        let mut pal = [0; 3 * 256];
        let _ = RasterMut::new(
                ::std::usize::MAX, ::std::usize::MAX, &mut buf, &mut pal);
    }
}
<|endoftext|>


<commit_before>use std::io::Read;

use errors::{Result, ErrorKind};
use message::Message;

use byteorder::ReadBytesExt;
use byteorder::LittleEndian as LE;

const WIRE_TYPE_VARINT: u8 = 0;
const WIRE_TYPE_FIXED64: u8 = 1;
const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
const WIRE_TYPE_START_GROUP: u8 = 3;
const WIRE_TYPE_END_GROUP: u8 = 4;
const WIRE_TYPE_FIXED32: u8 = 5;

/// A struct to read protocol binary files
pub struct Reader<R> {
    inner: R,
    len: usize,
}

impl<R: Read> Reader<R> {

    /// Creates a new protocol buffer reader with the maximum len of bytes to read
    pub fn from_reader(r: R, len: usize) -> Reader<R> {
        Reader { inner: r, len: len }
    }

    /// Reads next tag, `None` if all bytes have been read
    pub fn next_tag_value(&mut self) -> Option<Result<u32>> {
        if self.len == 0 {
            None
        } else {
            Some(self.read_varint().map(|i| (i as u32)))
        }
    }

    fn read_varint(&mut self) -> Result<u64> {
        let mut r: u64 = 0;
        let mut i = 0;
        for _ in 0..9 {
            self.len -= 1;
            let b = self.inner.read_u8()?;
            r |= ((b & 0x7f) as u64) << i;
            if b < 0x80 {
                return Ok(r);
            }
            i += 7;
        }
        self.len -= 1;
        match self.inner.read_u8()? {
            0 => Ok(r),
            1 => {
                r |= 1 << 63;
                Ok(r)
            }
            _ => Err(ErrorKind::Varint.into()), // we have only one spare bit to fit into
        }
    }

    pub fn read_int32(&mut self) -> Result<i32> {
        self.read_varint().map(|i| i as i32)
    }

    pub fn read_int64(&mut self) -> Result<i64> {
        self.read_varint().map(|i| i as i64)
    }

    pub fn read_uint32(&mut self) -> Result<u32> {
        self.read_varint().map(|i| i as u32)
    }

    pub fn read_uint64(&mut self) -> Result<u64> {
        self.read_varint()
    }

    pub fn read_sint32(&mut self) -> Result<i32> {
        // zigzag
        let n = self.read_varint()? as u32;
        Ok(((n >> 1) as i32) ^ (-((n & 1) as i32)))
    }

    pub fn read_sint64(&mut self) -> Result<i64> {
        // zigzag
        let n = self.read_varint()?;
        Ok(((n >> 1) as i64) ^ (-((n & 1) as i64)))
    }

    pub fn read_fixed64(&mut self) -> Result<u64> {
        self.len -= 8;
        self.inner.read_u64::<LE>().map_err(|e| e.into())
    }

    pub fn read_fixed32(&mut self) -> Result<u32> {
        self.len -= 4;
        self.inner.read_u32::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed64(&mut self) -> Result<i64> {
        self.len -= 8;
        self.inner.read_i64::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed32(&mut self) -> Result<i32> {
        self.len -= 4;
        self.inner.read_i32::<LE>().map_err(|e| e.into())
    }

    pub fn read_float(&mut self) -> Result<f32> {
        self.len -= 4;
        self.inner.read_f32::<LE>().map_err(|e| e.into())
    }

    pub fn read_double(&mut self) -> Result<f64> {
        self.len -= 8;
        self.inner.read_f64::<LE>().map_err(|e| e.into())
    }

    pub fn read_bool(&mut self) -> Result<bool> {
        self.read_varint().map(|i| i != 0)
    }

    pub fn read_enum<E: From<u64>>(&mut self) -> Result<E> {
        self.read_varint().map(|i| i.into())
    }

    pub fn read_bytes(&mut self) -> Result<Vec<u8>> {
        let len = self.read_varint()? as usize;
        self.len -= len;
        let mut vec = Vec::with_capacity(len);
        unsafe { vec.set_len(len); }
        self.inner.read_exact(&mut vec[..])?;
        Ok(vec)
    }

    pub fn read_string(&mut self) -> Result<String> {
        let vec = self.read_bytes()?;
        String::from_utf8(vec).map_err(|e| e.into())
    }

    pub fn read_packed_repeated_field<M, F: FnMut(&mut Self) -> Result<M>>(&mut self, mut read: F) -> Result<Vec<M>> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let mut v = Vec::new();
        while self.len > 0 {
            v.push(read(self)?);
        }
        self.len = cur_len - len;
        Ok(v)
    }

    pub fn read_message<M: Message>(&mut self) -> Result<M> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let msg = M::from_reader(self)?;
        self.len = cur_len - len;
        Ok(msg)
    }

    pub fn read_unknown(&mut self, tag_value: u32) -> Result<()> {
        match (tag_value & 0x7) as u8 {
            WIRE_TYPE_VARINT => { self.read_varint()?; },
            WIRE_TYPE_FIXED64 => {
                self.len -= 8;
                self.inner.read_exact(&mut [0; 8])?;
            }
            WIRE_TYPE_FIXED32 => {
                self.len -= 4;
                self.inner.read_exact(&mut [0; 4])?;
            }
            WIRE_TYPE_LENGTH_DELIMITED => {
                let len = self.read_varint()? as usize;
                if len == 0 { return Ok(()); }
                self.len -= len;
                let mut buf = Vec::with_capacity(len);
                unsafe { buf.set_len(len); }
                self.inner.read_exact(&mut buf)?;
            },
            WIRE_TYPE_START_GROUP |
                WIRE_TYPE_END_GROUP => { return Err(ErrorKind::Deprecated("group").into()); },
            t => { return Err(ErrorKind::UnknownWireType(t).into()); },
        }
        Ok(())
    }

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

#[test]
fn test_varint() {
    let data: &[u8] = &[0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag().is_none());
}

#[test]
fn test_next_field() {
    let data: &[u8] = &[0x08, 0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    let tag = r.next_tag().unwrap().unwrap();
    assert_eq!((1, WireType::Varint), tag.unpack());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag().is_none());
}
<commit_msg>remove broken test on tag decoding<commit_after>use std::io::Read;

use errors::{Result, ErrorKind};
use message::Message;

use byteorder::ReadBytesExt;
use byteorder::LittleEndian as LE;

const WIRE_TYPE_VARINT: u8 = 0;
const WIRE_TYPE_FIXED64: u8 = 1;
const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
const WIRE_TYPE_START_GROUP: u8 = 3;
const WIRE_TYPE_END_GROUP: u8 = 4;
const WIRE_TYPE_FIXED32: u8 = 5;

/// A struct to read protocol binary files
pub struct Reader<R> {
    inner: R,
    len: usize,
}

impl<R: Read> Reader<R> {

    /// Creates a new protocol buffer reader with the maximum len of bytes to read
    pub fn from_reader(r: R, len: usize) -> Reader<R> {
        Reader { inner: r, len: len }
    }

    /// Reads next tag, `None` if all bytes have been read
    pub fn next_tag_value(&mut self) -> Option<Result<u32>> {
        if self.len == 0 {
            None
        } else {
            Some(self.read_varint().map(|i| (i as u32)))
        }
    }

    fn read_varint(&mut self) -> Result<u64> {
        let mut r: u64 = 0;
        let mut i = 0;
        for _ in 0..9 {
            self.len -= 1;
            let b = self.inner.read_u8()?;
            r |= ((b & 0x7f) as u64) << i;
            if b < 0x80 {
                return Ok(r);
            }
            i += 7;
        }
        self.len -= 1;
        match self.inner.read_u8()? {
            0 => Ok(r),
            1 => {
                r |= 1 << 63;
                Ok(r)
            }
            _ => Err(ErrorKind::Varint.into()), // we have only one spare bit to fit into
        }
    }

    pub fn read_int32(&mut self) -> Result<i32> {
        self.read_varint().map(|i| i as i32)
    }

    pub fn read_int64(&mut self) -> Result<i64> {
        self.read_varint().map(|i| i as i64)
    }

    pub fn read_uint32(&mut self) -> Result<u32> {
        self.read_varint().map(|i| i as u32)
    }

    pub fn read_uint64(&mut self) -> Result<u64> {
        self.read_varint()
    }

    pub fn read_sint32(&mut self) -> Result<i32> {
        // zigzag
        let n = self.read_varint()? as u32;
        Ok(((n >> 1) as i32) ^ (-((n & 1) as i32)))
    }

    pub fn read_sint64(&mut self) -> Result<i64> {
        // zigzag
        let n = self.read_varint()?;
        Ok(((n >> 1) as i64) ^ (-((n & 1) as i64)))
    }

    pub fn read_fixed64(&mut self) -> Result<u64> {
        self.len -= 8;
        self.inner.read_u64::<LE>().map_err(|e| e.into())
    }

    pub fn read_fixed32(&mut self) -> Result<u32> {
        self.len -= 4;
        self.inner.read_u32::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed64(&mut self) -> Result<i64> {
        self.len -= 8;
        self.inner.read_i64::<LE>().map_err(|e| e.into())
    }

    pub fn read_sfixed32(&mut self) -> Result<i32> {
        self.len -= 4;
        self.inner.read_i32::<LE>().map_err(|e| e.into())
    }

    pub fn read_float(&mut self) -> Result<f32> {
        self.len -= 4;
        self.inner.read_f32::<LE>().map_err(|e| e.into())
    }

    pub fn read_double(&mut self) -> Result<f64> {
        self.len -= 8;
        self.inner.read_f64::<LE>().map_err(|e| e.into())
    }

    pub fn read_bool(&mut self) -> Result<bool> {
        self.read_varint().map(|i| i != 0)
    }

    pub fn read_enum<E: From<u64>>(&mut self) -> Result<E> {
        self.read_varint().map(|i| i.into())
    }

    pub fn read_bytes(&mut self) -> Result<Vec<u8>> {
        let len = self.read_varint()? as usize;
        self.len -= len;
        let mut vec = Vec::with_capacity(len);
        unsafe { vec.set_len(len); }
        self.inner.read_exact(&mut vec[..])?;
        Ok(vec)
    }

    pub fn read_string(&mut self) -> Result<String> {
        let vec = self.read_bytes()?;
        String::from_utf8(vec).map_err(|e| e.into())
    }

    pub fn read_packed_repeated_field<M, F: FnMut(&mut Self) -> Result<M>>(&mut self, mut read: F) -> Result<Vec<M>> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let mut v = Vec::new();
        while self.len > 0 {
            v.push(read(self)?);
        }
        self.len = cur_len - len;
        Ok(v)
    }

    pub fn read_message<M: Message>(&mut self) -> Result<M> {
        let len = self.read_varint()? as usize;
        let cur_len = self.len;
        self.len = len;
        let msg = M::from_reader(self)?;
        self.len = cur_len - len;
        Ok(msg)
    }

    pub fn read_unknown(&mut self, tag_value: u32) -> Result<()> {
        match (tag_value & 0x7) as u8 {
            WIRE_TYPE_VARINT => { self.read_varint()?; },
            WIRE_TYPE_FIXED64 => {
                self.len -= 8;
                self.inner.read_exact(&mut [0; 8])?;
            }
            WIRE_TYPE_FIXED32 => {
                self.len -= 4;
                self.inner.read_exact(&mut [0; 4])?;
            }
            WIRE_TYPE_LENGTH_DELIMITED => {
                let len = self.read_varint()? as usize;
                if len == 0 { return Ok(()); }
                self.len -= len;
                let mut buf = Vec::with_capacity(len);
                unsafe { buf.set_len(len); }
                self.inner.read_exact(&mut buf)?;
            },
            WIRE_TYPE_START_GROUP |
                WIRE_TYPE_END_GROUP => { return Err(ErrorKind::Deprecated("group").into()); },
            t => { return Err(ErrorKind::UnknownWireType(t).into()); },
        }
        Ok(())
    }

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

#[test]
fn test_varint() {
    let data: &[u8] = &[0x96, 0x01];
    let mut r = Reader::from_reader(data, data.len());
    assert_eq!(150, r.read_varint().unwrap());
    assert!(r.next_tag_value().is_none());
}
<|endoftext|>


<commit_before>macro_rules! begin_rescuable {
    ($param:expr, $t:ty, $i:ident) => (
        let mut $i = |v: $t| {};

        macro_rules! on_rescue {
            ($v:ident, $e:expr, $j:ident) => (
                let mut $j = |$v: $t| {
                    $e;
                    $j($v);
                };
            )
        }

        macro_rules! trr {
            ($e:expr, $j:ident) => (match $e {
                Ok(val) => val,
                Err(err) => {
                    return $j($param);
                }
            });
        }

        macro_rules! end_rescuable {
            ($j:ident) => (
                ::std::mem::forget($j);
            )
        }
    )
}
<commit_msg>Problem: rescuable closure might capture droppable values Solution: forget -> drop<commit_after>macro_rules! begin_rescuable {
    ($param:expr, $t:ty, $i:ident) => (
        let mut $i = |v: $t| {};

        macro_rules! on_rescue {
            ($v:ident, $e:expr, $j:ident) => (
                let mut $j = |$v: $t| {
                    $e;
                    $j($v);
                };
            )
        }

        macro_rules! trr {
            ($e:expr, $j:ident) => (match $e {
                Ok(val) => val,
                Err(err) => {
                    return $j($param);
                }
            });
        }

        macro_rules! end_rescuable {
            ($j:ident) => (
                ::std::mem::drop($j);
            )
        }
    )
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate futures;
extern crate redis;

use futures::Future;
use futures::future::ok as FutureOk;

use hyper::{Client, Body, Uri, StatusCode};
use hyper::server::{Request, Response, Service};
use hyper::client::HttpConnector;
use hyper::error::UriError;
use hyper::Get;

use std::sync::Arc;

use host_resolver::HostResolver;

use redis_service;

#[derive(Clone)]
pub struct Proxy {
    pub client: Client<HttpConnector, Body>,
    pub host_resolver: Arc<HostResolver>,
}

impl Proxy {

    pub fn new(client: Client<HttpConnector, Body>, host_resolver: Arc<HostResolver>) -> Proxy {
        Proxy { client, host_resolver }
    }
}

impl Service for Proxy {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item=Self::Response, Error = Self::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        info!("Dispatching request: {:?}", &req);
        Router::new(self.host_resolver.clone()).dispatch_request(&self.client, req)
    }
}

#[derive(Clone)]
pub struct Router {
    max_retry: Arc<u32>,
    host_resolver: Arc<HostResolver>
}

impl Router {

    pub fn new(host_resolver: Arc<HostResolver>) -> Router {
        Router { max_retry: Arc::new(3), host_resolver: host_resolver }
    }

    fn clone_req(req: &Request) -> Request {
        let mut new_req = Request::new(req.method().clone(), req.uri().clone());
        new_req.headers_mut().extend(req.headers().iter());
        new_req
    }

    fn clone_req_custom_uri(req: &Request, uri: &Uri) -> Request {
        let mut new_req = Request::new(req.method().clone(), uri.clone());
        new_req.headers_mut().extend(req.headers().iter());
        new_req
    }

    fn create_url(host: &str, uri: Uri) -> Result<Uri, UriError> {
        format!("{}{}{}", host, uri.path(), uri.query().unwrap_or("")).parse()
    }

    fn map_req(&self, req: Request) -> Request {
        let host = self.host_resolver.clone().get_next();
        let uri = Self::create_url(host.as_ref(), req.uri().clone())
            .expect(&format!("Failed trying to parse uri. Origin: {:?}", &req.uri()));
        Self::clone_req_custom_uri(&req, &uri)
    }

    fn req_is_cacheable(req: & Request<Body>) -> bool {
        (*req.method() == Get) // TODO check header Cache: False
    }

    fn cache_key(req: &Request<Body>) -> String {
        req.uri().path().clone().to_string()
    }

    fn dispatch_request(self, client: &Client<HttpConnector, Body>, req: Request<Body>) -> Box<Future<Error=hyper::Error, Item=Response>> {
        if Self::req_is_cacheable(&req) {
            self.with_cache(client, req)
        } else {
            self.forward_to_server(client, req, 1)
        }
    }

    fn with_cache(self, client: &Client<HttpConnector, Body>, req: Request<Body>) -> Box<Future<Error=hyper::Error, Item=Response>> {
        let redis_conn = Arc::new(redis_service::create_connection());
        let cache_key = Self::cache_key(&req);
        let cache_response = redis_service::get(redis_conn.clone(), cache_key);
        let resp: Box<Future<Error=hyper::Error, Item=Response>> = match cache_response {
        	//TODO FALTA EL RETURN
            Ok(response) =>  {
                info!("Response from Redis: {:?}", response);
                Box::new(FutureOk(Response::new().with_body(response)))
            },
            Err(e) => {
                let resp = self
                    .forward_to_server(client, req, 1)
                    .and_then(move |response| {
                        Router::try_cache(redis_conn.clone(), String::from(""));
                        FutureOk(response)
                    });
                Box::new(resp)
            }
        };
//        Box::new(resp)
        resp
    }

    fn try_cache(redis_conn: Arc<redis::Connection>, key: String) {
        redis_service::set(redis_conn, key, String::from(""));
    }

    fn forward_to_server(self, client: &Client<HttpConnector, Body>, req: Request<Body>, n_retry: u32) -> Box<Future<Error=hyper::Error, Item=Response>>
    {

        let client_clone = client.clone();
        let ref_max = self.max_retry.clone();

        let cloned_req = self.map_req(Self::clone_req(&req));

        info!("Attemp {} for url: {:?}", n_retry, cloned_req);

        let resp = client.request(Self::clone_req(&cloned_req)).then(move |result| {
            debug!("Max retry: {}. Current attemp: {}", ref_max.clone(), n_retry);
            match result {
                Ok(client_resp) => {
                    if client_resp.status() == hyper::StatusCode::Ok {
                        Box::new(FutureOk(client_resp))
                    } else if (n_retry < *ref_max.clone()) && (*cloned_req.method() == Get) {
                        self.forward_to_server(&client_clone, Self::clone_req(&cloned_req), n_retry + 1)
                    } else {
                        Box::new(FutureOk(Response::new().with_status(StatusCode::ServiceUnavailable)))
                    }
                },
                Err(e) => {
                    error!("Connection error: {:?}", &e);
                    if n_retry < *ref_max.clone() {
                        self.forward_to_server(&client_clone, Self::clone_req(&cloned_req), n_retry + 1)
                    } else {
                        Box::new(FutureOk(Response::new().with_status(StatusCode::ServiceUnavailable)))
                    }

                }
            }
        });
//        redis_service::set(redis_service::create_connection(),req.uri().path().clone().to_string(),
//        	resp.map(|body| {
//                        Response::new()
//                            .with_body(body)
//                    })
//        );
        Box::new(resp)
    }
}
<commit_msg>save body of cacheable request on cache<commit_after>extern crate hyper;
extern crate futures;
extern crate redis;

use futures::Future;
use futures::Stream;
use futures::future::ok as FutureOk;

use hyper::{Client, Body, Uri, StatusCode};
use hyper::server::{Request, Response, Service};
use hyper::client::HttpConnector;
use hyper::error::UriError;
use hyper::Get;

use hyper::header::ContentLength;

use std::sync::Arc;

use host_resolver::HostResolver;

use redis_service;

#[derive(Clone)]
pub struct Proxy {
    pub client: Client<HttpConnector, Body>,
    pub host_resolver: Arc<HostResolver>,
}

impl Proxy {

    pub fn new(client: Client<HttpConnector, Body>, host_resolver: Arc<HostResolver>) -> Proxy {
        Proxy { client, host_resolver }
    }
}

impl Service for Proxy {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item=Self::Response, Error = Self::Error>>;

    fn call(&self, req: Self::Request) -> Self::Future {
        info!("Dispatching request: {:?}", &req);
        Router::new(self.host_resolver.clone()).dispatch_request(&self.client, req)
    }
}

#[derive(Clone)]
pub struct Router {
    max_retry: Arc<u32>,
    host_resolver: Arc<HostResolver>
}

impl Router {

    pub fn new(host_resolver: Arc<HostResolver>) -> Router {
        Router { max_retry: Arc::new(3), host_resolver: host_resolver }
    }

    fn clone_req(req: &Request) -> Request {
        let mut new_req = Request::new(req.method().clone(), req.uri().clone());
        new_req.headers_mut().extend(req.headers().iter());
        new_req
    }

    fn clone_req_custom_uri(req: &Request, uri: &Uri) -> Request {
        let mut new_req = Request::new(req.method().clone(), uri.clone());
        new_req.headers_mut().extend(req.headers().iter());
        new_req
    }

    fn create_url(host: &str, uri: Uri) -> Result<Uri, UriError> {
        format!("{}{}{}", host, uri.path(), uri.query().unwrap_or("")).parse()
    }

    fn map_req(&self, req: Request) -> Request {
        let host = self.host_resolver.clone().get_next();
        let uri = Self::create_url(host.as_ref(), req.uri().clone())
            .expect(&format!("Failed trying to parse uri. Origin: {:?}", &req.uri()));
        Self::clone_req_custom_uri(&req, &uri)
    }

    fn req_is_cacheable(req: & Request<Body>) -> bool {
        (*req.method() == Get) // TODO check header Cache: False
    }

    fn cache_key(req: &Request<Body>) -> String {
        req.uri().path().clone().to_string()
    }

    fn dispatch_request(self, client: &Client<HttpConnector, Body>, req: Request<Body>) -> Box<Future<Error=hyper::Error, Item=Response>> {
        if Self::req_is_cacheable(&req) {
            self.with_cache(client, req)
        } else {
            self.forward_to_server(client, req, 1)
        }
    }

    fn with_cache(self, client: &Client<HttpConnector, Body>, req: Request<Body>) -> Box<Future<Error=hyper::Error, Item=Response>> {
        let redis_conn = Arc::new(redis_service::create_connection());
        let cache_key = Self::cache_key(&req);
        let cache_response = redis_service::get(redis_conn.clone(), cache_key);
        let resp: Box<Future<Error=hyper::Error, Item=Response>> = match cache_response {
        	//TODO FALTA EL RETURN
            Ok(response) =>  {
                info!("Response from Redis: {:?}", response);
                Box::new(FutureOk(Response::new().with_body(response)))
            },
            Err(e) => {
                let resp = self
                    .forward_to_server(client, req, 1)
                    .and_then(move |response| {
                        let resp = response
                            .body()
                            .fold(Vec::new(), |mut acc, chunk| {
                                acc.extend_from_slice(&*chunk);
                                futures::future::ok::<_, hyper::Error>(acc)
                            })
                            .map(move |body| {
                                let body_str = String::from_utf8(body).unwrap();
                                Router::try_cache(redis_conn.clone(), body_str.clone());
                                let resp: Response<Body> = Response::new()
                                    .with_header(ContentLength(body_str.len() as u64))
                                    .with_body(body_str.clone());
                                resp
                            });
                        Box::new(resp)
                    });
                Box::new(resp)
            }
        };
        resp
    }

    fn try_cache(redis_conn: Arc<redis::Connection>, key: String) {
        redis_service::set(redis_conn, key, String::from(""));
    }

    fn forward_to_server(self, client: &Client<HttpConnector, Body>, req: Request<Body>, n_retry: u32) -> Box<Future<Error=hyper::Error, Item=Response>>
    {

        let client_clone = client.clone();
        let ref_max = self.max_retry.clone();

        let cloned_req = self.map_req(Self::clone_req(&req));

        info!("Attemp {} for url: {:?}", n_retry, cloned_req);

        let resp = client.request(Self::clone_req(&cloned_req)).then(move |result| {
            debug!("Max retry: {}. Current attemp: {}", ref_max.clone(), n_retry);
            match result {
                Ok(client_resp) => {
                    if client_resp.status() == hyper::StatusCode::Ok {
                        Box::new(FutureOk(client_resp))
                    } else if (n_retry < *ref_max.clone()) && (*cloned_req.method() == Get) {
                        self.forward_to_server(&client_clone, Self::clone_req(&cloned_req), n_retry + 1)
                    } else {
                        Box::new(FutureOk(Response::new().with_status(StatusCode::ServiceUnavailable)))
                    }
                },
                Err(e) => {
                    error!("Connection error: {:?}", &e);
                    if n_retry < *ref_max.clone() {
                        self.forward_to_server(&client_clone, Self::clone_req(&cloned_req), n_retry + 1)
                    } else {
                        Box::new(FutureOk(Response::new().with_status(StatusCode::ServiceUnavailable)))
                    }

                }
            }
        });
//        redis_service::set(redis_service::create_connection(),req.uri().path().clone().to_string(),
//        	resp.map(|body| {
//                        Response::new()
//                            .with_body(body)
//                    })
//        );
        Box::new(resp)
    }
}
<|endoftext|>


<commit_before>use sha1::Sha1;

use cmd::cmd;
use types::{ToRedisArgs, FromRedisValue, RedisResult, ErrorKind};
use connection::ConnectionLike;

/// Represents a lua script.
pub struct Script {
    code: String,
    hash: String,
}

/// The script object represents a lua script that can be executed on the
/// redis server.  The object itself takes care of automatic uploading and
/// execution.  The script object itself can be shared and is immutable.
///
/// Example:
///
/// ```rust,no_run
/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// # let con = client.get_connection().unwrap();
/// let script = redis::Script::new(r"
///     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
/// ");
/// let result = script.arg(1).arg(2).invoke(&con);
/// assert_eq!(result, Ok(3));
/// ```
impl Script {

    /// Creates a new script object.
    pub fn new(code: &str) -> Script {
        let mut hash = Sha1::new();
        hash.update(code.as_bytes());
        Script {
            code: code.to_string(),
            hash: hash.hexdigest(),
        }
    }

    /// Returns the script's SHA1 hash in hexadecimal format.
    pub fn get_hash(&self) -> &str {
        &self.hash
    }

    /// Creates a script invocation object with a key filled in.
    #[inline]
    pub fn key<T: ToRedisArgs>(&self, key: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: key.to_redis_args(),
        }
    }

    /// Creates a script invocation object with an argument filled in.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&self, arg: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: arg.to_redis_args(),
            keys: vec![],
        }
    }

    /// Returns an empty script invocation object.  This is primarily useful
    /// for programmatically adding arguments and keys because the type will
    /// not change.  Normally you can use `arg` and `key` directly.
    #[inline]
    pub fn prepare_invoke(&self) -> ScriptInvocation {
        ScriptInvocation { script: self, args: vec![], keys: vec![] }
    }

    /// Invokes the script directly without arguments.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &ConnectionLike) -> RedisResult<T> {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: vec![],
        }.invoke(con)
    }
}

/// Represents a prepared script call.
pub struct ScriptInvocation<'a> {
    script: &'a Script,
    args: Vec<Vec<u8>>,
    keys: Vec<Vec<u8>>,
}

/// This type collects keys and other arguments for the script so that it
/// can be then invoked.  While the `Script` type itself holds the script,
/// the `ScriptInvocation` holds the arguments that should be invoked until
/// it's sent to the server.
impl<'a> ScriptInvocation<'a> {

    /// Adds a regular argument to the invocation.  This ends up as `ARGV[i]`
    /// in the script.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&'a mut self, arg: T) -> &'a mut ScriptInvocation {
        self.args.extend(arg.to_redis_args().into_iter());
        self
    }

    /// Adds a key argument to the invocation.  This ends up as `KEYS[i]`
    /// in the script.
    #[inline]
    pub fn key<T: ToRedisArgs>(&'a mut self, key: T) -> &'a mut ScriptInvocation {
        self.keys.extend(key.to_redis_args().into_iter());
        self
    }

    /// Invokes the script and returns the result.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &ConnectionLike) -> RedisResult<T> {
        loop {
            match cmd("EVALSHA")
                .arg(self.script.hash.as_bytes())
                .arg(self.keys.len())
                .arg(&*self.keys)
                .arg(&*self.args).query(con) {
                Ok(val) => { return Ok(val); }
                Err(err) => {
                    if err.kind() == ErrorKind::NoScriptError {
                        let _ : () = try!(cmd("SCRIPT")
                            .arg("LOAD")
                            .arg(self.script.code.as_bytes())
                            .query(con));
                    } else {
                        fail!(err);
                    }
                }
            }
        }
    }
}
<commit_msg>Fixed new sha1 api<commit_after>use sha1::Sha1;

use cmd::cmd;
use types::{ToRedisArgs, FromRedisValue, RedisResult, ErrorKind};
use connection::ConnectionLike;

/// Represents a lua script.
pub struct Script {
    code: String,
    hash: String,
}

/// The script object represents a lua script that can be executed on the
/// redis server.  The object itself takes care of automatic uploading and
/// execution.  The script object itself can be shared and is immutable.
///
/// Example:
///
/// ```rust,no_run
/// # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// # let con = client.get_connection().unwrap();
/// let script = redis::Script::new(r"
///     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
/// ");
/// let result = script.arg(1).arg(2).invoke(&con);
/// assert_eq!(result, Ok(3));
/// ```
impl Script {

    /// Creates a new script object.
    pub fn new(code: &str) -> Script {
        let mut hash = Sha1::new();
        hash.update(code.as_bytes());
        Script {
            code: code.to_string(),
            hash: hash.digest().to_string(),
        }
    }

    /// Returns the script's SHA1 hash in hexadecimal format.
    pub fn get_hash(&self) -> &str {
        &self.hash
    }

    /// Creates a script invocation object with a key filled in.
    #[inline]
    pub fn key<T: ToRedisArgs>(&self, key: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: key.to_redis_args(),
        }
    }

    /// Creates a script invocation object with an argument filled in.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&self, arg: T) -> ScriptInvocation {
        ScriptInvocation {
            script: self,
            args: arg.to_redis_args(),
            keys: vec![],
        }
    }

    /// Returns an empty script invocation object.  This is primarily useful
    /// for programmatically adding arguments and keys because the type will
    /// not change.  Normally you can use `arg` and `key` directly.
    #[inline]
    pub fn prepare_invoke(&self) -> ScriptInvocation {
        ScriptInvocation { script: self, args: vec![], keys: vec![] }
    }

    /// Invokes the script directly without arguments.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &ConnectionLike) -> RedisResult<T> {
        ScriptInvocation {
            script: self,
            args: vec![],
            keys: vec![],
        }.invoke(con)
    }
}

/// Represents a prepared script call.
pub struct ScriptInvocation<'a> {
    script: &'a Script,
    args: Vec<Vec<u8>>,
    keys: Vec<Vec<u8>>,
}

/// This type collects keys and other arguments for the script so that it
/// can be then invoked.  While the `Script` type itself holds the script,
/// the `ScriptInvocation` holds the arguments that should be invoked until
/// it's sent to the server.
impl<'a> ScriptInvocation<'a> {

    /// Adds a regular argument to the invocation.  This ends up as `ARGV[i]`
    /// in the script.
    #[inline]
    pub fn arg<T: ToRedisArgs>(&'a mut self, arg: T) -> &'a mut ScriptInvocation {
        self.args.extend(arg.to_redis_args().into_iter());
        self
    }

    /// Adds a key argument to the invocation.  This ends up as `KEYS[i]`
    /// in the script.
    #[inline]
    pub fn key<T: ToRedisArgs>(&'a mut self, key: T) -> &'a mut ScriptInvocation {
        self.keys.extend(key.to_redis_args().into_iter());
        self
    }

    /// Invokes the script and returns the result.
    #[inline]
    pub fn invoke<T: FromRedisValue>(&self, con: &ConnectionLike) -> RedisResult<T> {
        loop {
            match cmd("EVALSHA")
                .arg(self.script.hash.as_bytes())
                .arg(self.keys.len())
                .arg(&*self.keys)
                .arg(&*self.args).query(con) {
                Ok(val) => { return Ok(val); }
                Err(err) => {
                    if err.kind() == ErrorKind::NoScriptError {
                        let _ : () = try!(cmd("SCRIPT")
                            .arg("LOAD")
                            .arg(self.script.code.as_bytes())
                            .query(con));
                    } else {
                        fail!(err);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use std::sync::mpsc::{self, SyncSender, SendError, Receiver, TryRecvError};
use std::sync::Arc;
use std::time::Duration;
use std::thread;

use rotor::{self, Scope, Time};
use rotor::mio::tcp::TcpListener;
use rotor::void::Void;
use rotor_http::server::{RecvMode, Server, Head, Response, Fsm};
use rotor_tools::timer::{IntervalFunc, interval_func};

use super::context::Context;
use super::handler::Handler;
use super::http_status;

rotor_compose!(enum Machine/Seed<Context> {
    Http(Fsm<Responder, TcpListener>),
    Timer(IntervalFunc<Context>),
});

pub struct Guard(SyncSender<()>);

impl Guard {
    pub fn stop(self) -> Result<(), SendError<()>> {
        self.0.send(())
    }
}

fn create_interval(scope: &mut Scope<Context>, duration: Duration, rx: Receiver<()>)
-> rotor::Response<IntervalFunc<Context>, Void>
{
    interval_func(scope, duration, move |scope: &mut Scope<Context>| {
        match rx.try_recv() {
            Ok(_) | Err(TryRecvError::Disconnected) => {
                info!("Stopping server");
                scope.shutdown_loop();
            }
            _ => {},
        }
    })
}

pub fn start(context: Context, address: &str)
    -> Result<Guard, String>
{
    let (tx, rx) = mpsc::sync_channel::<()>(0);

    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
            .wrap(|fsm| Machine::Http(fsm))
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        create_interval(scope, Duration::new(1, 0), rx)
            .wrap(|fsm| Machine::Timer(fsm))
    }).map_err(|e| format!("{}", e)));

    thread::spawn(move || {
        loop_inst.run().unwrap();
    });

    Ok(Guard(tx))
}

pub fn run(context: Context, address: &str)
    -> Result<(), String>
{
    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.run().map_err(|e| format!("{}", e)));

    Ok(())
}

pub trait Router {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>>;
}

impl Router for Context {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>> {
        for ref route in self.routes().iter() {
            if route.is_match(method, path) {
                return Some(route.handler())
            }
        }
        None
    }
}

pub type MethodPath = (String, String);

#[derive(Clone, Debug)]
pub enum Responder {
    Respond(Arc<Handler>, (MethodPath)),
    NotFound(MethodPath),
}

fn send_not_found(res: &mut Response) {
    let data = b"404 - Page not found";
    let status = http_status::NotFound;
    res.status(status.code(), status.description());
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

fn send_error(res: &mut Response, data: &str) {
    let data = data.as_bytes();
    let status = http_status::InternalServerError;
    res.status(status.code(), status.description());
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

impl Server for Responder {
    type Seed = ();
    type Context = Context;

    fn headers_received(_seed: Self::Seed, head: Head, _res: &mut Response,
        scope: &mut Scope<Self::Context>)
        -> Option<(Self, RecvMode, Time)>
    {
        if scope.autoreload() {
            match scope.rebuild() {
                Ok(_) => {}
                Err(e) => {
                    error!("{}", e);
                    return None
                }
            }
        }

        let mp = (head.method.to_owned(), head.path.to_owned());
        let responder = match scope.match_route(head.method, head.path) {
            Some(handler) => Responder::Respond(handler.clone(), mp),
            None => Responder::NotFound(mp),
        };

        Some((responder, RecvMode::Buffered(1024), scope.now() + Duration::new(10, 0)))
    }

    fn request_received(self, _data: &[u8], res: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<Self>
    {
        let method_path: MethodPath;
        let status: u16;
        let result = match self {
            Responder::Respond(handler, mp) => {
                method_path = mp;
                status = handler.status;
                handler.handle(res)
            },
            Responder::NotFound(mp) => {
                method_path = mp;
                status = 404;
                match scope.not_found_handler() {
                    Some(ref handler) => handler.handle(res),
                    None => { send_not_found(res); Ok(()) },
                }
            }
        };

        // info!("{} {}", handler.status, http_status::description(handler.status));

        result
        .map(|_| {
            if status == 404 {
                warn!("{} {} {}", status, method_path.0, method_path.1);
            } else {
                info!("{} {} {}", status, method_path.0, method_path.1);
            }
        })
        .map_err(|e| {
            error!("500 {} {}", method_path.0, method_path.1);
            error!("{}", &e);
            send_error(res, &e)
        })
        .ok();

        None
    }

    fn request_chunk(self, _chunk: &[u8], _response: &mut Response,
        _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    /// End of request body, only for Progressive requests
    fn request_end(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    fn timeout(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<(Self, Time)>
    {
        unimplemented!();
    }

    fn wakeup(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::time::Duration;
    use context::Context;
    use super::start as start_server;

    #[test]
    fn server_shutdown() {
        let context = Context::new();
        let guard = start_server(context, "127.0.0.1:7000").unwrap();
        guard.stop().unwrap();
    }
}
<commit_msg>Remove commented code<commit_after>use std::net::SocketAddr;
use std::sync::mpsc::{self, SyncSender, SendError, Receiver, TryRecvError};
use std::sync::Arc;
use std::time::Duration;
use std::thread;

use rotor::{self, Scope, Time};
use rotor::mio::tcp::TcpListener;
use rotor::void::Void;
use rotor_http::server::{RecvMode, Server, Head, Response, Fsm};
use rotor_tools::timer::{IntervalFunc, interval_func};

use super::context::Context;
use super::handler::Handler;
use super::http_status;

rotor_compose!(enum Machine/Seed<Context> {
    Http(Fsm<Responder, TcpListener>),
    Timer(IntervalFunc<Context>),
});

pub struct Guard(SyncSender<()>);

impl Guard {
    pub fn stop(self) -> Result<(), SendError<()>> {
        self.0.send(())
    }
}

fn create_interval(scope: &mut Scope<Context>, duration: Duration, rx: Receiver<()>)
-> rotor::Response<IntervalFunc<Context>, Void>
{
    interval_func(scope, duration, move |scope: &mut Scope<Context>| {
        match rx.try_recv() {
            Ok(_) | Err(TryRecvError::Disconnected) => {
                info!("Stopping server");
                scope.shutdown_loop();
            }
            _ => {},
        }
    })
}

pub fn start(context: Context, address: &str)
    -> Result<Guard, String>
{
    let (tx, rx) = mpsc::sync_channel::<()>(0);

    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
            .wrap(|fsm| Machine::Http(fsm))
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        create_interval(scope, Duration::new(1, 0), rx)
            .wrap(|fsm| Machine::Timer(fsm))
    }).map_err(|e| format!("{}", e)));

    thread::spawn(move || {
        loop_inst.run().unwrap();
    });

    Ok(Guard(tx))
}

pub fn run(context: Context, address: &str)
    -> Result<(), String>
{
    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.run().map_err(|e| format!("{}", e)));

    Ok(())
}

pub trait Router {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>>;
}

impl Router for Context {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>> {
        for ref route in self.routes().iter() {
            if route.is_match(method, path) {
                return Some(route.handler())
            }
        }
        None
    }
}

pub type MethodPath = (String, String);

#[derive(Clone, Debug)]
pub enum Responder {
    Respond(Arc<Handler>, (MethodPath)),
    NotFound(MethodPath),
}

fn send_not_found(res: &mut Response) {
    let data = b"404 - Page not found";
    let status = http_status::NotFound;
    res.status(status.code(), status.description());
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

fn send_error(res: &mut Response, data: &str) {
    let data = data.as_bytes();
    let status = http_status::InternalServerError;
    res.status(status.code(), status.description());
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

impl Server for Responder {
    type Seed = ();
    type Context = Context;

    fn headers_received(_seed: Self::Seed, head: Head, _res: &mut Response,
        scope: &mut Scope<Self::Context>)
        -> Option<(Self, RecvMode, Time)>
    {
        if scope.autoreload() {
            match scope.rebuild() {
                Ok(_) => {}
                Err(e) => {
                    error!("{}", e);
                    return None
                }
            }
        }

        let mp = (head.method.to_owned(), head.path.to_owned());
        let responder = match scope.match_route(head.method, head.path) {
            Some(handler) => Responder::Respond(handler.clone(), mp),
            None => Responder::NotFound(mp),
        };

        Some((responder, RecvMode::Buffered(1024), scope.now() + Duration::new(10, 0)))
    }

    fn request_received(self, _data: &[u8], res: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<Self>
    {
        let method_path: MethodPath;
        let status: u16;
        let result = match self {
            Responder::Respond(handler, mp) => {
                method_path = mp;
                status = handler.status;
                handler.handle(res)
            },
            Responder::NotFound(mp) => {
                method_path = mp;
                status = 404;
                match scope.not_found_handler() {
                    Some(ref handler) => handler.handle(res),
                    None => { send_not_found(res); Ok(()) },
                }
            }
        };

        result
        .map(|_| {
            if status == 404 {
                warn!("{} {} {}", status, method_path.0, method_path.1);
            } else {
                info!("{} {} {}", status, method_path.0, method_path.1);
            }
        })
        .map_err(|e| {
            error!("500 {} {}", method_path.0, method_path.1);
            error!("{}", &e);
            send_error(res, &e)
        })
        .ok();

        None
    }

    fn request_chunk(self, _chunk: &[u8], _response: &mut Response,
        _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    /// End of request body, only for Progressive requests
    fn request_end(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    fn timeout(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<(Self, Time)>
    {
        unimplemented!();
    }

    fn wakeup(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::time::Duration;
    use context::Context;
    use super::start as start_server;

    #[test]
    fn server_shutdown() {
        let context = Context::new();
        let guard = start_server(context, "127.0.0.1:7000").unwrap();
        guard.stop().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender};

use std::io::prelude::*;
//use std::io::BufReader;

extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;
extern crate rand;

use self::uuid::Uuid;

use client::{Client,ClientBase};
use chat::{read_text,text_as_bytes};
use distributor::Distributor;
use distributor::Kind as DistKind;
use store::{DataStore,Store};
use player::Player;

pub struct Server {
    clients: Vec<ClientBase>, // this always grows
    players: HashMap<Uuid, Player>,
    pub dist_tx: Sender<DistKind<TcpStream>>,
    store: Store,
}

impl Server {
    pub fn new(ip: &str) {
        let listener = TcpListener::bind(ip).unwrap();

        let (dist_tx,mut dist) = Distributor::new(Store::default());
        thread::spawn(move || dist.run());

        let mut server = Server {
            clients: vec!(),
            players: HashMap::new(),
            dist_tx: dist_tx,
            store: Store::default(),
        };

        server.clients = server.store.clients_get();

        let server = Arc::new(Mutex::new(server));

        for s in listener.incoming() {
            match s {
                Ok(s) => {
                    let server = server.clone();
                    thread::spawn(|| Server::handler(server,s));
                },
                _ => {},
            }
        }
    }

    #[allow(unused_must_use)]
    fn handler (mut server: Arc<Mutex<Server>>, mut s: TcpStream) {
        let mut cmd = [0;1];

        //new conn needs auth code
        let m = uuid::Uuid::new_v4();
        s.write_all(m.as_bytes());

        let mut client_id: Option<Uuid> = None;

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    0 => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_nicks(&mut server, uuid);
                        }
                    },
                    1 => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                2 => { //chat
                                    Server::chat(&mut server, &mut s, uuid);
                                },
                                3 => { //nick
                                    Server::nick(&mut server, &mut s, uuid);
                                },
                                _ => panic!("unknown cmd:{:?}",cmd)
                            }
                        }
                    }
                }
            }
            else { break } //drop dead client
        }

        println!("client dropped");
    }

    fn register (server: &mut Arc<Mutex<Server>>,
                 mut s: &mut TcpStream,) {
        if let Some(c) = Client::load(&mut s) {
            let mut server = server.lock().unwrap();

            for n in server.clients.iter() {
                if &n.id == c.id() { continue }
            }

            let mut r = false;
            for _ in [..100].iter() { // try to repeatedly add a unique name
                let mut nick = "player_".to_string();
                nick.push_str(&rand::random::<u16>().to_string());
                r = server.store.player_put(&c.id(), &Player { nick: nick });
                if r { break }
            }

            if r {
                let r = server.store.client_put(&c.base);
                println!("registered ({:?}):{:?}",r, c.id());
                server.clients.push(c.base);
            }
        }
    }

    #[allow(unused_must_use)]
    fn chat (server: &mut Arc<Mutex<Server>>,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            println!("chat-client:{:?}",text.trim());

            //broadcast
            let (mut data, bytes) = text_as_bytes(&text);
            data.extend_from_slice(bytes);

            let server = server.lock().unwrap();
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

            server.dist_tx.send(DistKind::Broadcast(data));
        }
    }

    #[allow(unused_must_use)]
    fn nick (server: &mut Arc<Mutex<Server>>,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            let r = {
                let server = server.lock().unwrap();
                server.store.player_update(&uuid, &Player { nick: text.clone() })
            };

            if r {
                Server::send_nick(server, uuid,&text);
                println!("nick_change:{:?}  {:?}",uuid,text);
            }
        }
    }
     #[allow(unused_must_use)]
    fn send_nick (server: &mut Arc<Mutex<Server>>,
                  uuid: Uuid,
                  nick: &String) {
        //broadcast
        let (mut data, bytes) = text_as_bytes(nick);
        data[0] = 3; //change opcode to nick
        data.extend_from_slice(bytes);
        data.extend_from_slice(uuid.as_bytes()); //refer to uuid

        let server = server.lock().unwrap();
        server.dist_tx.send(DistKind::Broadcast(data));
    }

    #[allow(unused_must_use)]
    fn login (server: &mut Arc<Mutex<Server>>,
              mut s: &mut TcpStream,
              m: Uuid) -> Option<Uuid> {
        let mut client_id = None;
        let mut player = None;

        if let Some(c) = Client::load(&mut s) {
            let mut reg_key = None;

            {
                let mut server = server.lock().unwrap();
                for n in server.clients.iter_mut() {
                    if &n.id == c.id() {
                        reg_key = Some(n.key.clone());
                        client_id = Some(c.id().clone());

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {
                    {
                        let mut server = server.lock().unwrap();
                        player = server.store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                let mut server = server.lock().unwrap();
                                server.dist_tx.send(DistKind::Add(*c.id(),stmp));
                                server.players.insert(*c.id(),player.clone());
                                println!("total players:{:?}",server.players.len());
                            }

                            println!("login:{:?}",c.id());
                            Server::send_nick(server, *c.id(), &player.nick);
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

            }
            else { panic!("client unregistered {:?}", c) }
        }

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_nicks (server: &mut Arc<Mutex<Server>>,
                   uuid: Uuid)  {
        let server = server.lock().unwrap();

        for (ref pid,player) in server.players.iter() {
            let (mut data, bytes) = text_as_bytes(&player.nick);
            data[0] = 3; // specify nick route

            data.extend_from_slice(bytes);
            data.extend_from_slice(pid.as_bytes()); //refer to uuid

            server.dist_tx.send(DistKind::Select(uuid,data));
        }
    }
}
<commit_msg>add fixme<commit_after>use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender};

use std::io::prelude::*;
//use std::io::BufReader;

extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;
extern crate rand;

use self::uuid::Uuid;

use client::{Client,ClientBase};
use chat::{read_text,text_as_bytes};
use distributor::Distributor;
use distributor::Kind as DistKind;
use store::{DataStore,Store};
use player::Player;

pub struct Server {
    clients: Vec<ClientBase>, // this always grows
    players: HashMap<Uuid, Player>,
    pub dist_tx: Sender<DistKind<TcpStream>>,
    store: Store,
}

impl Server {
    pub fn new(ip: &str) {
        let listener = TcpListener::bind(ip).unwrap();

        let (dist_tx,mut dist) = Distributor::new(Store::default());
        thread::spawn(move || dist.run());

        let mut server = Server {
            clients: vec!(),
            players: HashMap::new(),
            dist_tx: dist_tx,
            store: Store::default(),
        };

        server.clients = server.store.clients_get();
        let server = Arc::new(Mutex::new(server)); //FIXME: mutex glom needs to go

        for s in listener.incoming() {
            match s {
                Ok(s) => {
                    let server = server.clone();
                    thread::spawn(|| Server::handler(server,s));
                },
                _ => {},
            }
        }
    }

    #[allow(unused_must_use)]
    fn handler (mut server: Arc<Mutex<Server>>, mut s: TcpStream) {
        let mut cmd = [0;1];

        //new conn needs auth code
        let m = uuid::Uuid::new_v4();
        s.write_all(m.as_bytes());

        let mut client_id: Option<Uuid> = None;

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    0 => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_nicks(&mut server, uuid);
                        }
                    },
                    1 => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                2 => { //chat
                                    Server::chat(&mut server, &mut s, uuid);
                                },
                                3 => { //nick
                                    Server::nick(&mut server, &mut s, uuid);
                                },
                                _ => panic!("unknown cmd:{:?}",cmd)
                            }
                        }
                    }
                }
            }
            else { break } //drop dead client
        }

        println!("client dropped");
    }

    fn register (server: &mut Arc<Mutex<Server>>,
                 mut s: &mut TcpStream,) {
        if let Some(c) = Client::load(&mut s) {
            let mut server = server.lock().unwrap();

            for n in server.clients.iter() {
                if &n.id == c.id() { continue }
            }

            let mut r = false;
            for _ in [..100].iter() { // try to repeatedly add a unique name
                let mut nick = "player_".to_string();
                nick.push_str(&rand::random::<u16>().to_string());
                r = server.store.player_put(&c.id(), &Player { nick: nick });
                if r { break }
            }

            if r {
                let r = server.store.client_put(&c.base);
                println!("registered ({:?}):{:?}",r, c.id());
                server.clients.push(c.base);
            }
        }
    }

    #[allow(unused_must_use)]
    fn chat (server: &mut Arc<Mutex<Server>>,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            println!("chat-client:{:?}",text.trim());

            //broadcast
            let (mut data, bytes) = text_as_bytes(&text);
            data.extend_from_slice(bytes);

            let server = server.lock().unwrap();
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

            server.dist_tx.send(DistKind::Broadcast(data));
        }
    }

    #[allow(unused_must_use)]
    fn nick (server: &mut Arc<Mutex<Server>>,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            let r = {
                let server = server.lock().unwrap();
                server.store.player_update(&uuid, &Player { nick: text.clone() })
            };

            if r {
                Server::send_nick(server, uuid,&text);
                println!("nick_change:{:?}  {:?}",uuid,text);
            }
        }
    }
     #[allow(unused_must_use)]
    fn send_nick (server: &mut Arc<Mutex<Server>>,
                  uuid: Uuid,
                  nick: &String) {
        //broadcast
        let (mut data, bytes) = text_as_bytes(nick);
        data[0] = 3; //change opcode to nick
        data.extend_from_slice(bytes);
        data.extend_from_slice(uuid.as_bytes()); //refer to uuid

        let server = server.lock().unwrap();
        server.dist_tx.send(DistKind::Broadcast(data));
    }

    #[allow(unused_must_use)]
    fn login (server: &mut Arc<Mutex<Server>>,
              mut s: &mut TcpStream,
              m: Uuid) -> Option<Uuid> {
        let mut client_id = None;
        let mut player = None;

        if let Some(c) = Client::load(&mut s) {
            let mut reg_key = None;

            {
                let mut server = server.lock().unwrap();
                for n in server.clients.iter_mut() {
                    if &n.id == c.id() {
                        reg_key = Some(n.key.clone());
                        client_id = Some(c.id().clone());

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {
                    {
                        let mut server = server.lock().unwrap();
                        player = server.store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                let mut server = server.lock().unwrap();
                                server.dist_tx.send(DistKind::Add(*c.id(),stmp));
                                server.players.insert(*c.id(),player.clone());
                                println!("total players:{:?}",server.players.len());
                            }

                            println!("login:{:?}",c.id());
                            Server::send_nick(server, *c.id(), &player.nick);
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

            }
            else { panic!("client unregistered {:?}", c) }
        }

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_nicks (server: &mut Arc<Mutex<Server>>,
                   uuid: Uuid)  {
        let server = server.lock().unwrap();

        for (ref pid,player) in server.players.iter() {
            let (mut data, bytes) = text_as_bytes(&player.nick);
            data[0] = 3; // specify nick route

            data.extend_from_slice(bytes);
            data.extend_from_slice(pid.as_bytes()); //refer to uuid

            server.dist_tx.send(DistKind::Select(uuid,data));
        }
    }
}
<|endoftext|>


<commit_before>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::{now, Tm};
use mysql;
use std::process;

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};
use data_parser::{parse_text_data, StationDataType};

fn write_xml_data(tm: Tm, local_port: u16, data: &StationDataType, file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.xml", file_name))));

    let date_time_format = "%Y-%m-%d %H:%M:%S";

    let current_date_time = tm.strftime(&date_time_format).unwrap();

    try!(write!(file_handle, "<measure>\n"));
    try!(write!(file_handle, "<port>{}</port>\n", local_port));
    try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
    try!(write!(file_handle, "<data>\n"));

    // try!(write!(file_handle, "{:?}\n", data));

    match data {
        &StationDataType::SingleData(time_stamp_tm, voltage) => {
            if let Ok(time_stamp) = time_stamp_tm.strftime(&date_time_format) {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <voltage>{}</voltage>\n", voltage));
            }
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            if let Ok(time_stamp) = full_data_set.time_stamp.strftime(&date_time_format) {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <air_temperature>{}</air_temperature>\n", full_data_set.air_temperature));
                try!(write!(file_handle, "    <air_relative_humidity>{}</air_relative_humidity>\n", full_data_set.air_relative_humidity));
                try!(write!(file_handle, "    <solar_radiation>{}</solar_radiation>\n", full_data_set.solar_radiation));
                try!(write!(file_handle, "    <soil_water_content>{}</soil_water_content>\n", full_data_set.soil_water_content));
                try!(write!(file_handle, "    <soil_temperature>{}</soil_temperature>\n", full_data_set.soil_temperature));
                try!(write!(file_handle, "    <wind_speed>{}</wind_speed>\n", full_data_set.wind_speed));
                try!(write!(file_handle, "    <wind_max>{}</wind_max>\n", full_data_set.wind_max));
                try!(write!(file_handle, "    <wind_direction>{}</wind_direction>\n", full_data_set.wind_direction));
                try!(write!(file_handle, "    <precipitation>{}</precipitation>\n", full_data_set.precipitation));
                try!(write!(file_handle, "    <air_pressure>{}</air_pressure>\n", full_data_set.air_pressure));
            }
        }
    }

    try!(write!(file_handle, "</data>\n"));
    try!(write!(file_handle, "</measure>\n\n"));

    Ok(())
}

fn write_csv_data(data: &StationDataType, file_name: &str) -> Result<()> {
    let mut file_handle = BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.csv", file_name))));

        let date_time_format = "%Y-%m-%d %H:%M:%S";

        match data {
            &StationDataType::SingleData(time_stamp_tm, voltage) => {
                if let Ok(time_stamp) = time_stamp_tm.strftime(&date_time_format) {
                    try!(write!(file_handle, "\"{}\", {}\n", time_stamp, voltage));
                }
            },
            &StationDataType::MultipleData(ref full_data_set) => {
                if let Ok(time_stamp) = full_data_set.time_stamp.strftime(&date_time_format) {
                    try!(write!(file_handle, "\"{}\", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}\n",
                        time_stamp,
                        full_data_set.air_temperature,
                        full_data_set.air_relative_humidity,
                        full_data_set.solar_radiation,
                        full_data_set.soil_water_content,
                        full_data_set.soil_temperature,
                        full_data_set.wind_speed,
                        full_data_set.wind_max,
                        full_data_set.wind_direction,
                        full_data_set.precipitation,
                        full_data_set.air_pressure
                    ));
                }
            }
        }

    Ok(())
}

fn write_to_db(db_pool: &mysql::Pool, station_folder: &str, data: &StationDataType) -> Result<()> {

    Ok(())
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        2104 => "2104_Tue".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>,
    db_pool: &Arc<Mutex<mysql::Pool>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    if buffer.len() > HEADER_LENGTH {
        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII): '{}'", str_header);
        info!("Data (ASCII): '{}'", str_data);

        let station_folder = port_to_station(local_port);

        match parse_text_data(&buffer_right) {
            Ok(parsed_data) => {
                info!("Data parsed correctly");
                match all_data_file.lock() {
                    Ok(all_data_file) => {
                        let tm = now();
                        let file_name = format!("{}/{}", station_folder, *all_data_file);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
                }

                match monthly_data_folder.lock() {
                    Ok(monthly_data_folder) => {
                        let tm = now();
                        let current_year = tm.strftime("%Y").unwrap();
                        let current_month = tm.strftime("%m").unwrap();
                        // TODO: create separate folder for year and month in Rust
                        let file_name = format!("{}/{}/{}_{}", *monthly_data_folder, station_folder, current_year, current_month);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
                }
                match db_pool.lock() {
                    Ok(db_pool) => {
                        try!(write_to_db(&db_pool, &station_folder, &parsed_data));
                    },
                    Err(e) => info!("Mutex (poison) error (db_pool): {}", e)
                }
            },
            Err(e) => {
                info!("Could not parse data: {}", e);
            }
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    info!("handle_client finished");

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => {
                info!("Network error: {}", e);
                process::exit(1);
            }
        }
    }

    let mut db_builder = mysql::OptsBuilder::new();
    db_builder.ip_or_hostname(Some(config.hostname))
           .db_name(Some(config.db_name))
           .user(Some(config.username))
           .pass(Some(config.password));
    let db_pool = match mysql::Pool::new(db_builder) {
        Ok(db_pool) => db_pool,
        Err(e) => {
            info!("Database error: {}", e);
            process::exit(1);
        }
    };

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));
    let db_pool = Arc::new(Mutex::new(db_pool));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        let cloned_pool = db_pool.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder, &cloned_pool) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}

#[cfg(test)]
mod tests {
    use time::strptime;
    use data_parser::StationDataType;
    use time::{now};
    use mysql;

    use super::{write_csv_data, write_xml_data, write_to_db, port_to_station};

    #[test]
    fn test_port_to_station() {
        assert_eq!(port_to_station(2100), "2100_Na");
        assert_eq!(port_to_station(2101), "2101_SG");
        assert_eq!(port_to_station(2102), "2102_PdA");
        assert_eq!(port_to_station(2103), "2103_LC");
        assert_eq!(port_to_station(2104), "2104_Tue");
        assert_eq!(port_to_station(2105), "unknown");
    }

    #[test]
    fn test_write_csv_data1() {
        assert!(write_csv_data(&StationDataType::SingleData(strptime("2016-06-12 00:00:00",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73), "/does_not_work/does_not_work.csv").is_err());
    }

    #[test]
    fn test_write_xml_data1() {
        assert!(write_xml_data(now(), 0, &StationDataType::SingleData(strptime("2016-06-12 00:00:00",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73), "/does_not_work/does_not_work.csv").is_err());
    }

    #[test]
    fn test_write_to_db1() {
        let mut db_builder = mysql::OptsBuilder::new();
        db_builder.ip_or_hostname(Some("localhost"))
                  .tcp_port(3306)
                  .user(Some("test"))
                  .pass(Some("test"))
                  .db_name(Some("test_weatherstation"));
        let pool = mysql::Pool::new(db_builder).unwrap();

        assert!(write_to_db(&pool, "2101_SG", &StationDataType::SingleData(strptime("2016-06-12 00:00:00",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73)).is_ok());
    }

}
<commit_msg>more MySQL support<commit_after>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io;
use time::{now, Tm};
use mysql;
use mysql::{OptsBuilder, Pool, Value};
use std::process;

// Internal modules:
use configuration::{Configuration, HEADER_LENGTH};
use data_parser::{parse_text_data, StationDataType};

quick_error! {
    #[derive(Debug)]
    enum StoreDataError {
        IOError(error: io::Error) {
            from()
        }
        MySQLError(error: mysql::Error) {
            from()
        }
    }
}

fn write_xml_data(tm: Tm, local_port: u16, data: &StationDataType, file_name: &str) -> Result<(), StoreDataError> {
    let mut file_handle = io::BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.xml", file_name))));

    let date_time_format = "%Y-%m-%d %H:%M:%S";

    let current_date_time = tm.strftime(&date_time_format).unwrap();

    try!(write!(file_handle, "<measure>\n"));
    try!(write!(file_handle, "<port>{}</port>\n", local_port));
    try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
    try!(write!(file_handle, "<data>\n"));

    // try!(write!(file_handle, "{:?}\n", data));

    match data {
        &StationDataType::SingleData(time_stamp_tm, voltage) => {
            if let Ok(time_stamp) = time_stamp_tm.strftime(&date_time_format) {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <voltage>{}</voltage>\n", voltage));
            }
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            if let Ok(time_stamp) = full_data_set.time_stamp.strftime(&date_time_format) {
                try!(write!(file_handle, "    <time_stamp>{}</time_stamp>\n", time_stamp));
                try!(write!(file_handle, "    <air_temperature>{}</air_temperature>\n", full_data_set.air_temperature));
                try!(write!(file_handle, "    <air_relative_humidity>{}</air_relative_humidity>\n", full_data_set.air_relative_humidity));
                try!(write!(file_handle, "    <solar_radiation>{}</solar_radiation>\n", full_data_set.solar_radiation));
                try!(write!(file_handle, "    <soil_water_content>{}</soil_water_content>\n", full_data_set.soil_water_content));
                try!(write!(file_handle, "    <soil_temperature>{}</soil_temperature>\n", full_data_set.soil_temperature));
                try!(write!(file_handle, "    <wind_speed>{}</wind_speed>\n", full_data_set.wind_speed));
                try!(write!(file_handle, "    <wind_max>{}</wind_max>\n", full_data_set.wind_max));
                try!(write!(file_handle, "    <wind_direction>{}</wind_direction>\n", full_data_set.wind_direction));
                try!(write!(file_handle, "    <precipitation>{}</precipitation>\n", full_data_set.precipitation));
                try!(write!(file_handle, "    <air_pressure>{}</air_pressure>\n", full_data_set.air_pressure));
            }
        }
    }

    try!(write!(file_handle, "</data>\n"));
    try!(write!(file_handle, "</measure>\n\n"));

    Ok(())
}

fn write_csv_data(data: &StationDataType, file_name: &str) -> Result<(), StoreDataError> {
    let mut file_handle = io::BufWriter::new(try!(OpenOptions::new()
        .write(true).create(true).append(true).open(format!("{}.csv", file_name))));

        let date_time_format = "%Y-%m-%d %H:%M:%S";

        match data {
            &StationDataType::SingleData(time_stamp_tm, voltage) => {
                if let Ok(time_stamp) = time_stamp_tm.strftime(&date_time_format) {
                    try!(write!(file_handle, "\"{}\", {}\n", time_stamp, voltage));
                }
            },
            &StationDataType::MultipleData(ref full_data_set) => {
                if let Ok(time_stamp) = full_data_set.time_stamp.strftime(&date_time_format) {
                    try!(write!(file_handle, "\"{}\", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}\n",
                        time_stamp,
                        full_data_set.air_temperature,
                        full_data_set.air_relative_humidity,
                        full_data_set.solar_radiation,
                        full_data_set.soil_water_content,
                        full_data_set.soil_temperature,
                        full_data_set.wind_speed,
                        full_data_set.wind_max,
                        full_data_set.wind_direction,
                        full_data_set.precipitation,
                        full_data_set.air_pressure
                    ));
                }
            }
        }

    Ok(())
}

fn write_to_db(db_pool: &Pool, station_folder: &str, data: &StationDataType) -> Result<(), StoreDataError> {
    let date_time_format = "%Y-%m-%d %H:%M:%S";

    match data {
        &StationDataType::SingleData(time_stamp_tm, voltage) => {
            if let Ok(time_stamp) = time_stamp_tm.strftime(&date_time_format) {
                let time_stamp = format!("{}", time_stamp);
                try!(db_pool.prep_exec("insert into battery_data (timestamp, station,
                    battery_voltage) values (:timestamp, :station, :battery_voltage)",
                    (Value::from(time_stamp), Value::from(station_folder), Value::from(voltage))));
            }
        },
        &StationDataType::MultipleData(ref full_data_set) => {
            if let Ok(time_stamp) = full_data_set.time_stamp.strftime(&date_time_format) {
                // TODO
            }
        }
    }

    Ok(())
}

fn port_to_station(port: u16) -> String{
    match port {
        2100 => "2100_Na".to_string(),
        2101 => "2101_SG".to_string(),
        2102 => "2102_PdA".to_string(),
        2103 => "2103_LC".to_string(),
        2104 => "2104_Tue".to_string(),
        _ => "unknown".to_string()
    }
}

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>,
    db_pool: &Arc<Mutex<Pool>>) -> Result<(), StoreDataError> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);

    if buffer.len() > HEADER_LENGTH {
        let (buffer_left, buffer_right) = buffer.split_at(HEADER_LENGTH);

        let str_header = String::from_utf8_lossy(buffer_left);
        let str_data = String::from_utf8_lossy(buffer_right);

        info!("Header: {:?}", buffer_left);
        info!("Data: {:?}", buffer_right);

        info!("Header (ASCII): '{}'", str_header);
        info!("Data (ASCII): '{}'", str_data);

        let station_folder = port_to_station(local_port);

        match parse_text_data(&buffer_right) {
            Ok(parsed_data) => {
                info!("Data parsed correctly");
                match all_data_file.lock() {
                    Ok(all_data_file) => {
                        let tm = now();
                        let file_name = format!("{}/{}", station_folder, *all_data_file);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
                }

                match monthly_data_folder.lock() {
                    Ok(monthly_data_folder) => {
                        let tm = now();
                        let current_year = tm.strftime("%Y").unwrap();
                        let current_month = tm.strftime("%m").unwrap();
                        // TODO: create separate folder for year and month in Rust
                        let file_name = format!("{}/{}/{}_{}", *monthly_data_folder, station_folder, current_year, current_month);
                        try!(write_xml_data(tm, local_port, &parsed_data, &file_name));
                        try!(write_csv_data(&parsed_data, &file_name));
                    },
                    Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
                }
                match db_pool.lock() {
                    Ok(db_pool) => {
                        try!(write_to_db(&db_pool, &station_folder, &parsed_data));
                    },
                    Err(e) => info!("Mutex (poison) error (db_pool): {}", e)
                }
            },
            Err(e) => {
                info!("Could not parse data: {}", e);
            }
        }
    } else if buffer.len() < HEADER_LENGTH {
        info!("Invalid header (less than {} bytes received)!", HEADER_LENGTH);
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    } else { // buffer.len() == HEADER_LENGTH -> no data, only header
        info!("No data received, just header.");
        info!("Bytes: {:?}", buffer);
        info!("Bytes (ASCII): '{}'", String::from_utf8_lossy(&buffer));
    }

    info!("handle_client finished");

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        match TcpListener::bind(("0.0.0.0", port)) {
            Ok(listener) => {
                info!("Create listener for port {}", port);
                listeners.push(listener);
            },
            Err(e) => {
                info!("Network error: {}", e);
                process::exit(1);
            }
        }
    }

    let mut db_builder = OptsBuilder::new();
    db_builder.ip_or_hostname(Some(config.hostname))
           .db_name(Some(config.db_name))
           .user(Some(config.username))
           .pass(Some(config.password));
    let db_pool = match Pool::new(db_builder) {
        Ok(db_pool) => db_pool,
        Err(e) => {
            info!("Database error: {}", e);
            process::exit(1);
        }
    };

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));
    let db_pool = Arc::new(Mutex::new(db_pool));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        let cloned_pool = db_pool.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(data_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder, &cloned_pool) {
                        info!("Store Data Error: {}", data_error);
                    }
                }
            }
        });
    }
}

#[cfg(test)]
mod tests {
    use time::strptime;
    use data_parser::StationDataType;
    use time::{now};
    use mysql;

    use super::{write_csv_data, write_xml_data, write_to_db, port_to_station};

    #[test]
    fn test_port_to_station() {
        assert_eq!(port_to_station(2100), "2100_Na");
        assert_eq!(port_to_station(2101), "2101_SG");
        assert_eq!(port_to_station(2102), "2102_PdA");
        assert_eq!(port_to_station(2103), "2103_LC");
        assert_eq!(port_to_station(2104), "2104_Tue");
        assert_eq!(port_to_station(2105), "unknown");
    }

    #[test]
    fn test_write_csv_data1() {
        assert!(write_csv_data(&StationDataType::SingleData(strptime("2016-06-12 00:00:00",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73), "/does_not_work/does_not_work.csv").is_err());
    }

    #[test]
    fn test_write_xml_data1() {
        assert!(write_xml_data(now(), 0, &StationDataType::SingleData(strptime("2016-06-12 00:00:00",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73), "/does_not_work/does_not_work.csv").is_err());
    }

    #[test]
    fn test_write_to_db1() {
        let mut db_builder = mysql::OptsBuilder::new();
        db_builder.ip_or_hostname(Some("localhost"))
                  .tcp_port(3306)
                  .user(Some("test"))
                  .pass(Some("test"))
                  .db_name(Some("test_weatherstation"));
        let pool = mysql::Pool::new(db_builder).unwrap();

        assert!(write_to_db(&pool, "test1", &StationDataType::SingleData(strptime("2016-06-12 00:00:00",
        "%Y-%m-%d %H:%M:%S").unwrap(), 12.73)).is_ok());
        // TODO: retrieve values, remove test data from database

    }

}
<|endoftext|>