<commit_before>use mio;
use mio::tcp::*;
use mio::{TryRead,TryWrite};
use rustc_serialize::json;
use std::fmt;

use super::{ChainRepl, ChainReplMsg, OpResp, Operation};

trait Codec {
    fn encode_response(&self, s: OpResp) -> Vec<u8>;
    fn process_operation<F: FnMut(ChainReplMsg)>(&self, token: mio::Token, slice: &[u8], to_parent: &mut F);
}

#[derive(Debug)]
pub struct LineConn<T> {
    socket: TcpStream,
    sock_status: mio::EventSet,
    token: mio::Token,
    read_buf: Vec<u8>,
    read_eof: bool,
    failed: bool,
    write_buf: Vec<u8>,
    codec: T,
}

impl<T: Codec + fmt::Debug> LineConn<T> {
    fn new(socket: TcpStream, token: mio::Token, codec: T) -> LineConn<T> {
        trace!("New client connection {:?} from {:?}", token, socket.local_addr());
        LineConn {
            socket: socket,
            sock_status: mio::EventSet::none(),
            token: token,
            read_buf: Vec::with_capacity(1024),
            write_buf: Vec::new(),
            read_eof: false,
            failed: false,
            codec: codec,
        }
    }

    pub fn initialize(&self, event_loop: &mut mio::EventLoop<ChainRepl>, token: mio::Token) {
        event_loop.register_opt(
                &self.socket,
                token,
                mio::EventSet::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot())
            .expect("event loop initialize");
    }

    // Event updates arrive here
    pub fn handle_event(&mut self, _event_loop: &mut mio::EventLoop<ChainRepl>, events: mio::EventSet) {
        self.sock_status.insert(events);
        trace!("LineConn::handle_event: {:?}; this time: {:?}; now: {:?}",
                self.socket.peer_addr(), events, self.sock_status);
    }

    // actions are processed here on down.

    pub fn process_rules<F: FnMut(ChainReplMsg)>(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>,
        to_parent: &mut F) -> bool {
        if self.sock_status.is_readable() {
            self.read();
            self.sock_status.remove(mio::EventSet::readable());
        }

        let changed = self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.write();
            self.sock_status.remove(mio::EventSet::writable());
        }

        if !self.is_closed() {
            self.reinitialize(event_loop)
        }
        changed
    }

    fn process_buffer<F: FnMut(ChainReplMsg)>(&mut self, to_parent: &mut F) -> bool {
        let mut prev = 0;
        let mut changed = false;
        trace!("{:?}: Read buffer: {:?}", self.socket.peer_addr(), self.read_buf);
        for n in self.read_buf.iter().enumerate()
                .filter_map(|(i, e)| if *e == '\n' as u8 { Some(i) } else { None } ) {
            trace!("{:?}: Pos: {:?}-{:?}; chunk: {:?}", self.socket.peer_addr(), prev, n, &self.read_buf[prev..n]);
            let slice = &self.read_buf[prev..n];
            self.codec.process_operation(self.token, slice, to_parent);
            changed = true;
            prev = n+1;
        }

        let remainder = self.read_buf[prev..].to_vec();
        trace!("{:?}: read Remainder: {}", self.socket.peer_addr(), remainder.len());
        self.read_buf = remainder;
        changed
    }

    fn read(&mut self) {
        let mut abuf = Vec::new();
        match self.socket.try_read_buf(&mut abuf) {
            Ok(Some(0)) => {
                trace!("{:?}: EOF!", self.socket.peer_addr());
                self.read_eof = true
            },
            Ok(Some(n)) => {
                trace!("{:?}: Read {}bytes", self.socket.peer_addr(), n);
                self.read_buf.extend(abuf);
            },
            Ok(None) => {
                trace!("{:?}: Noop!", self.socket.peer_addr());
            },
            Err(e) => {
                error!("got an error trying to read; err={:?}", e);
                self.failed =true;
            }
        }
    }

    fn write(&mut self) {
        match self.socket.try_write(&mut self.write_buf) {
            Ok(Some(n)) => {
                trace!("{:?}: Wrote {} of {} in buffer", self.socket.peer_addr(), n,
                    self.write_buf.len());
                self.write_buf = self.write_buf[n..].to_vec();
                trace!("{:?}: Now {:?}b", self.socket.peer_addr(), self.write_buf.len());
            },
            Ok(None) => {
                trace!("Write unready");
            },
            Err(e) => {
                error!("got an error trying to write; err={:?}", e);
                self.failed = true;
            }
        }
    }

    fn reinitialize(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>) {
        let mut flags = mio::EventSet::readable();
        if !self.write_buf.is_empty() {
            flags.insert(mio::EventSet::writable());
        }
        trace!("Registering {:?} with {:?}", self, flags);

        event_loop.reregister(
                &self.socket,
                self.token,
                flags,
                mio::PollOpt::oneshot()).expect("EventLoop#reinitialize")
    }

    pub fn is_closed(&self) -> bool {
        self.failed || (self.read_eof && self.write_buf.is_empty())
    }

    // Per item to output
    pub fn response(&mut self, s: OpResp) {
        debug!("{:?}: Response: {:?}", self.token, s);
        let chunk = self.codec.encode_response(s);
        self.write_buf.extend(chunk);
        self.write_buf.push('\n' as u8)
    }
}

#[derive(Debug)]
pub struct JsonPeer;

impl Codec for JsonPeer {
    fn encode_response(&self, s: OpResp) -> Vec<u8> {
        json::encode(&s).expect("Encode json response").as_bytes().to_vec()
    }

    fn process_operation<F: FnMut(ChainReplMsg)>(&self, token: mio::Token, slice: &[u8], to_parent: &mut F) {
        let (seqno, op) = json::decode(&String::from_utf8_lossy(slice)).expect("Decode peer operation");

        let cmd = ChainReplMsg::Operation(token, Some(seqno), op);
        debug!("Send! {:?}", cmd);
        to_parent(cmd);
    }
}

impl LineConn<JsonPeer> {
    pub fn upstream(socket: TcpStream, token: mio::Token) -> LineConn<JsonPeer> {
        Self::new(socket, token, JsonPeer)
    }
}

#[derive(Debug)]
pub struct PlainClient;

impl Codec for PlainClient {
    fn encode_response(&self, s: OpResp) -> Vec<u8> {
        format!("{:?}", s).as_bytes().to_vec()
    }

    // Per line of input
    fn process_operation<F: FnMut(ChainReplMsg)>(&self, token: mio::Token, slice: &[u8], to_parent: &mut F) {
        let op = if slice.is_empty() {
            Operation::Get
        } else {
            Operation::Set(String::from_utf8_lossy(slice).to_string())
        };

        let cmd = ChainReplMsg::Operation(token, None, op);
        debug!("Send! {:?}", cmd);
        to_parent(cmd);
    }
}

impl LineConn<PlainClient> {
    pub fn client(socket: TcpStream, token: mio::Token) -> LineConn<PlainClient> {
        Self::new(socket, token, PlainClient)
    }
}
<commit_msg>Re-jig command parsing a tad.<commit_after>use mio;
use mio::tcp::*;
use mio::{TryRead,TryWrite};
use rustc_serialize::json;
use std::fmt;

use super::{ChainRepl, ChainReplMsg, OpResp, Operation};

trait Codec {
    fn encode_response(&self, s: OpResp) -> Vec<u8>;
    fn parse_operation(&self, token: mio::Token, slice: &[u8]) -> ChainReplMsg;
}

#[derive(Debug)]
pub struct LineConn<T> {
    socket: TcpStream,
    sock_status: mio::EventSet,
    token: mio::Token,
    read_buf: Vec<u8>,
    read_eof: bool,
    failed: bool,
    write_buf: Vec<u8>,
    codec: T,
}

impl<T: Codec + fmt::Debug> LineConn<T> {
    fn new(socket: TcpStream, token: mio::Token, codec: T) -> LineConn<T> {
        trace!("New client connection {:?} from {:?}", token, socket.local_addr());
        LineConn {
            socket: socket,
            sock_status: mio::EventSet::none(),
            token: token,
            read_buf: Vec::with_capacity(1024),
            write_buf: Vec::new(),
            read_eof: false,
            failed: false,
            codec: codec,
        }
    }

    pub fn initialize(&self, event_loop: &mut mio::EventLoop<ChainRepl>, token: mio::Token) {
        event_loop.register_opt(
                &self.socket,
                token,
                mio::EventSet::readable(),
                mio::PollOpt::edge() | mio::PollOpt::oneshot())
            .expect("event loop initialize");
    }

    // Event updates arrive here
    pub fn handle_event(&mut self, _event_loop: &mut mio::EventLoop<ChainRepl>, events: mio::EventSet) {
        self.sock_status.insert(events);
        trace!("LineConn::handle_event: {:?}; this time: {:?}; now: {:?}",
                self.socket.peer_addr(), events, self.sock_status);
    }

    // actions are processed here on down.

    pub fn process_rules<F: FnMut(ChainReplMsg)>(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>,
        to_parent: &mut F) -> bool {
        if self.sock_status.is_readable() {
            self.read();
            self.sock_status.remove(mio::EventSet::readable());
        }

        let changed = self.process_buffer(to_parent);

        if self.sock_status.is_writable() {
            self.write();
            self.sock_status.remove(mio::EventSet::writable());
        }

        if !self.is_closed() {
            self.reinitialize(event_loop)
        }
        changed
    }

    fn process_buffer<F: FnMut(ChainReplMsg)>(&mut self, to_parent: &mut F) -> bool {
        let mut prev = 0;
        let mut changed = false;
        trace!("{:?}: Read buffer: {:?}", self.socket.peer_addr(), self.read_buf);
        for n in self.read_buf.iter().enumerate()
                .filter_map(|(i, e)| if *e == '\n' as u8 { Some(i) } else { None } ) {
            trace!("{:?}: Pos: {:?}-{:?}; chunk: {:?}", self.socket.peer_addr(), prev, n, &self.read_buf[prev..n]);
            let slice = &self.read_buf[prev..n];

            let cmd = self.codec.parse_operation(self.token, slice);
            debug!("Read message {:?}", cmd);
            to_parent(cmd);

            changed = true;
            prev = n+1;
        }

        let remainder = self.read_buf[prev..].to_vec();
        trace!("{:?}: read Remainder: {}", self.socket.peer_addr(), remainder.len());
        self.read_buf = remainder;
        changed
    }

    fn read(&mut self) {
        let mut abuf = Vec::new();
        match self.socket.try_read_buf(&mut abuf) {
            Ok(Some(0)) => {
                trace!("{:?}: EOF!", self.socket.peer_addr());
                self.read_eof = true
            },
            Ok(Some(n)) => {
                trace!("{:?}: Read {}bytes", self.socket.peer_addr(), n);
                self.read_buf.extend(abuf);
            },
            Ok(None) => {
                trace!("{:?}: Noop!", self.socket.peer_addr());
            },
            Err(e) => {
                error!("got an error trying to read; err={:?}", e);
                self.failed =true;
            }
        }
    }

    fn write(&mut self) {
        match self.socket.try_write(&mut self.write_buf) {
            Ok(Some(n)) => {
                trace!("{:?}: Wrote {} of {} in buffer", self.socket.peer_addr(), n,
                    self.write_buf.len());
                self.write_buf = self.write_buf[n..].to_vec();
                trace!("{:?}: Now {:?}b", self.socket.peer_addr(), self.write_buf.len());
            },
            Ok(None) => {
                trace!("Write unready");
            },
            Err(e) => {
                error!("got an error trying to write; err={:?}", e);
                self.failed = true;
            }
        }
    }

    fn reinitialize(&mut self, event_loop: &mut mio::EventLoop<ChainRepl>) {
        let mut flags = mio::EventSet::readable();
        if !self.write_buf.is_empty() {
            flags.insert(mio::EventSet::writable());
        }
        trace!("Registering {:?} with {:?}", self, flags);

        event_loop.reregister(
                &self.socket,
                self.token,
                flags,
                mio::PollOpt::oneshot()).expect("EventLoop#reinitialize")
    }

    pub fn is_closed(&self) -> bool {
        self.failed || (self.read_eof && self.write_buf.is_empty())
    }

    // Per item to output
    pub fn response(&mut self, s: OpResp) {
        debug!("{:?}: Response: {:?}", self.token, s);
        let chunk = self.codec.encode_response(s);
        self.write_buf.extend(chunk);
        self.write_buf.push('\n' as u8)
    }
}

#[derive(Debug)]
pub struct JsonPeer;

impl Codec for JsonPeer {
    fn encode_response(&self, s: OpResp) -> Vec<u8> {
        json::encode(&s).expect("Encode json response").as_bytes().to_vec()
    }

    fn parse_operation(&self, token: mio::Token, slice: &[u8]) -> ChainReplMsg {
        let (seqno, op) = json::decode(&String::from_utf8_lossy(slice)).expect("Decode peer operation");
        ChainReplMsg::Operation(token, Some(seqno), op)
    }
}

impl LineConn<JsonPeer> {
    pub fn upstream(socket: TcpStream, token: mio::Token) -> LineConn<JsonPeer> {
        Self::new(socket, token, JsonPeer)
    }
}

#[derive(Debug)]
pub struct PlainClient;

impl Codec for PlainClient {
    fn encode_response(&self, s: OpResp) -> Vec<u8> {
        format!("{:?}", s).as_bytes().to_vec()
    }

    // Per line of input
    fn parse_operation(&self, token: mio::Token, slice: &[u8]) -> ChainReplMsg {
        let op = if slice.is_empty() {
            Operation::Get
        } else {
            Operation::Set(String::from_utf8_lossy(slice).to_string())
        };
        ChainReplMsg::Operation(token, None, op)
    }
}

impl LineConn<PlainClient> {
    pub fn client(socket: TcpStream, token: mio::Token) -> LineConn<PlainClient> {
        Self::new(socket, token, PlainClient)
    }
}
<|endoftext|>


<commit_before>#![crate_name = "link"]
#![feature(collections, core, old_io, old_path, rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::old_io::fs::link;
use std::old_path::Path;

#[path="../common/util.rs"]
#[macro_use]
mod util;

static NAME : &'static str = "link";
static VERSION : &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let opts = [
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(err) => panic!("{}", err),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.len() != 2 {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] FILE1 FILE2", NAME);
        println!("");
        print!("{}", getopts::usage("Create a link named FILE2 to FILE1.", opts.as_slice()).as_slice());
        if matches.free.len() != 2 {
            return 1;
        }
        return 0;
    }

    let old = Path::new(matches.free[0].as_slice());
    let new = Path::new(matches.free[1].as_slice());

    match link(&old, &new) {
        Ok(_) => 0,
        Err(err) => {
            show_error!("{}", err);
            1
        }
    }
}
<commit_msg>Fix link.<commit_after>#![crate_name = "link"]
#![feature(rustc_private)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Michael Gehring <mg@ebfe.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;

use std::io::Write;
use std::fs::hard_link;
use std::path::Path;

#[path="../common/util.rs"]
#[macro_use]
mod util;

static NAME : &'static str = "link";
static VERSION : &'static str = "1.0.0";

pub fn uumain(args: Vec<String>) -> i32 {
    let opts = [
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(&args[1..], &opts) {
        Ok(m) => m,
        Err(err) => panic!("{}", err),
    };

    if matches.opt_present("version") {
        println!("{} {}", NAME, VERSION);
        return 0;
    }

    if matches.opt_present("help") || matches.free.len() != 2 {
        println!("{} {}", NAME, VERSION);
        println!("");
        println!("Usage:");
        println!("  {} [OPTIONS] FILE1 FILE2", NAME);
        println!("");
        print!("{}", getopts::usage("Create a link named FILE2 to FILE1.", &opts));
        if matches.free.len() != 2 {
            return 1;
        }
        return 0;
    }

    let old = Path::new(&matches.free[0]);
    let new = Path::new(&matches.free[1]);

    match hard_link(old, new) {
        Ok(_) => 0,
        Err(err) => {
            show_error!("{}", err);
            1
        }
    }
}
<|endoftext|>


<commit_before>//! Functions related to adding and removing indentation from lines of
//! text.
//!
//! The functions here can be used to uniformly indent or dedent
//! (unindent) word wrapped lines of text.

/// Indent each line by the given prefix.
///
/// # Examples
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("First line.\nSecond line.\n", "  "),
///            "  First line.\n  Second line.\n");
/// ```
///
/// When indenting, trailing whitespace is stripped from the prefix.
/// This means that empty lines remain empty afterwards:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("First line.\n\n\nSecond line.\n", "  "),
///            "  First line.\n\n\n  Second line.\n");
/// ```
///
/// Notice how `"\n\n\n"` remained as `"\n\n\n"`.
///
/// This feature is useful when you want to indent text and have a
/// space between your prefix and the text. In this case, you _don't_
/// want a trailing space on empty lines:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("foo = 123\n\nprint(foo)\n", "# "),
///            "# foo = 123\n#\n# print(foo)\n");
/// ```
///
/// Notice how `"\n\n"` became `"\n#\n"` instead of `"\n# \n"` which
/// would have trailing whitespace.
///
/// Leading and trailing whitespace coming from the text itself is
/// kept unchanged:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent(" \t  Foo   ", "->"), "-> \t  Foo   ");
/// ```
pub fn indent(s: &str, prefix: &str) -> String {
    // We know we'll need more than s.len() bytes for the output, but
    // without counting '\n' characters (which is somewhat slow), we
    // don't know exactly how much. However, we can preemptively do
    // the first doubling of the output size.
    let mut result = String::with_capacity(2 * s.len());
    let trimmed_prefix = prefix.trim_end();
    for (idx, line) in s.split_terminator('\n').enumerate() {
        if idx > 0 {
            result.push('\n');
        }
        if line.trim().is_empty() {
            result.push_str(trimmed_prefix);
        } else {
            result.push_str(prefix);
        }
        result.push_str(line);
    }
    if s.ends_with('\n') {
        // split_terminator will have eaten the final '\n'.
        result.push('\n');
    }
    result
}

/// Removes common leading whitespace from each line.
///
/// This function will look at each non-empty line and determine the
/// maximum amount of whitespace that can be removed from all lines:
///
/// ```
/// use textwrap::dedent;
///
/// assert_eq!(dedent("
///     1st line
///       2nd line
///     3rd line
/// "), "
/// 1st line
///   2nd line
/// 3rd line
/// ");
/// ```
pub fn dedent(s: &str) -> String {
    let mut prefix = "";
    let mut lines = s.lines();

    // We first search for a non-empty line to find a prefix.
    for line in &mut lines {
        let mut whitespace_idx = line.len();
        for (idx, ch) in line.char_indices() {
            if !ch.is_whitespace() {
                whitespace_idx = idx;
                break;
            }
        }

        // Check if the line had anything but whitespace
        if whitespace_idx < line.len() {
            prefix = &line[..whitespace_idx];
            break;
        }
    }

    // We then continue looking through the remaining lines to
    // possibly shorten the prefix.
    for line in &mut lines {
        let mut whitespace_idx = line.len();
        for ((idx, a), b) in line.char_indices().zip(prefix.chars()) {
            if a != b {
                whitespace_idx = idx;
                break;
            }
        }

        // Check if the line had anything but whitespace and if we
        // have found a shorter prefix
        if whitespace_idx < line.len() && whitespace_idx < prefix.len() {
            prefix = &line[..whitespace_idx];
        }
    }

    // We now go over the lines a second time to build the result.
    let mut result = String::new();
    for line in s.lines() {
        if line.starts_with(&prefix) && line.chars().any(|c| !c.is_whitespace()) {
            let (_, tail) = line.split_at(prefix.len());
            result.push_str(tail);
        }
        result.push('\n');
    }

    if result.ends_with('\n') && !s.ends_with('\n') {
        let new_len = result.len() - 1;
        result.truncate(new_len);
    }

    result
}

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

    #[test]
    fn indent_empty() {
        assert_eq!(indent("\n", "  "), "\n");
    }

    #[test]
    #[rustfmt::skip]
    fn indent_nonempty() {
        let text = [
            "  foo\n",
            "bar\n",
            "  baz\n",
        ].join("");
        let expected = [
            "//   foo\n",
            "// bar\n",
            "//   baz\n",
        ].join("");
        assert_eq!(indent(&text, "// "), expected);
    }

    #[test]
    #[rustfmt::skip]
    fn indent_empty_line() {
        let text = [
            "  foo",
            "bar",
            "",
            "  baz",
        ].join("\n");
        let expected = [
            "//   foo",
            "// bar",
            "//",
            "//   baz",
        ].join("\n");
        assert_eq!(indent(&text, "// "), expected);
    }

    #[test]
    fn dedent_empty() {
        assert_eq!(dedent(""), "");
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_multi_line() {
        let x = [
            "    foo",
            "  bar",
            "    baz",
        ].join("\n");
        let y = [
            "  foo",
            "bar",
            "  baz"
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_empty_line() {
        let x = [
            "    foo",
            "  bar",
            "   ",
            "    baz"
        ].join("\n");
        let y = [
            "  foo",
            "bar",
            "",
            "  baz"
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_blank_line() {
        let x = [
            "      foo",
            "",
            "        bar",
            "          foo",
            "          bar",
            "          baz",
        ].join("\n");
        let y = [
            "foo",
            "",
            "  bar",
            "    foo",
            "    bar",
            "    baz",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_whitespace_line() {
        let x = [
            "      foo",
            " ",
            "        bar",
            "          foo",
            "          bar",
            "          baz",
        ].join("\n");
        let y = [
            "foo",
            "",
            "  bar",
            "    foo",
            "    bar",
            "    baz",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_mixed_whitespace() {
        let x = [
            "\tfoo",
            "  bar",
        ].join("\n");
        let y = [
            "\tfoo",
            "  bar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_tabbed_whitespace() {
        let x = [
            "\t\tfoo",
            "\t\t\tbar",
        ].join("\n");
        let y = [
            "foo",
            "\tbar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_mixed_tabbed_whitespace() {
        let x = [
            "\t  \tfoo",
            "\t  \t\tbar",
        ].join("\n");
        let y = [
            "foo",
            "\tbar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_mixed_tabbed_whitespace2() {
        let x = [
            "\t  \tfoo",
            "\t    \tbar",
        ].join("\n");
        let y = [
            "\tfoo",
            "  \tbar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_preserve_no_terminating_newline() {
        let x = [
            "  foo",
            "    bar",
        ].join("\n");
        let y = [
            "foo",
            "  bar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }
}
<commit_msg>Fix small Clippy warning<commit_after>//! Functions related to adding and removing indentation from lines of
//! text.
//!
//! The functions here can be used to uniformly indent or dedent
//! (unindent) word wrapped lines of text.

/// Indent each line by the given prefix.
///
/// # Examples
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("First line.\nSecond line.\n", "  "),
///            "  First line.\n  Second line.\n");
/// ```
///
/// When indenting, trailing whitespace is stripped from the prefix.
/// This means that empty lines remain empty afterwards:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("First line.\n\n\nSecond line.\n", "  "),
///            "  First line.\n\n\n  Second line.\n");
/// ```
///
/// Notice how `"\n\n\n"` remained as `"\n\n\n"`.
///
/// This feature is useful when you want to indent text and have a
/// space between your prefix and the text. In this case, you _don't_
/// want a trailing space on empty lines:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent("foo = 123\n\nprint(foo)\n", "# "),
///            "# foo = 123\n#\n# print(foo)\n");
/// ```
///
/// Notice how `"\n\n"` became `"\n#\n"` instead of `"\n# \n"` which
/// would have trailing whitespace.
///
/// Leading and trailing whitespace coming from the text itself is
/// kept unchanged:
///
/// ```
/// use textwrap::indent;
///
/// assert_eq!(indent(" \t  Foo   ", "->"), "-> \t  Foo   ");
/// ```
pub fn indent(s: &str, prefix: &str) -> String {
    // We know we'll need more than s.len() bytes for the output, but
    // without counting '\n' characters (which is somewhat slow), we
    // don't know exactly how much. However, we can preemptively do
    // the first doubling of the output size.
    let mut result = String::with_capacity(2 * s.len());
    let trimmed_prefix = prefix.trim_end();
    for (idx, line) in s.split_terminator('\n').enumerate() {
        if idx > 0 {
            result.push('\n');
        }
        if line.trim().is_empty() {
            result.push_str(trimmed_prefix);
        } else {
            result.push_str(prefix);
        }
        result.push_str(line);
    }
    if s.ends_with('\n') {
        // split_terminator will have eaten the final '\n'.
        result.push('\n');
    }
    result
}

/// Removes common leading whitespace from each line.
///
/// This function will look at each non-empty line and determine the
/// maximum amount of whitespace that can be removed from all lines:
///
/// ```
/// use textwrap::dedent;
///
/// assert_eq!(dedent("
///     1st line
///       2nd line
///     3rd line
/// "), "
/// 1st line
///   2nd line
/// 3rd line
/// ");
/// ```
pub fn dedent(s: &str) -> String {
    let mut prefix = "";
    let mut lines = s.lines();

    // We first search for a non-empty line to find a prefix.
    for line in &mut lines {
        let mut whitespace_idx = line.len();
        for (idx, ch) in line.char_indices() {
            if !ch.is_whitespace() {
                whitespace_idx = idx;
                break;
            }
        }

        // Check if the line had anything but whitespace
        if whitespace_idx < line.len() {
            prefix = &line[..whitespace_idx];
            break;
        }
    }

    // We then continue looking through the remaining lines to
    // possibly shorten the prefix.
    for line in &mut lines {
        let mut whitespace_idx = line.len();
        for ((idx, a), b) in line.char_indices().zip(prefix.chars()) {
            if a != b {
                whitespace_idx = idx;
                break;
            }
        }

        // Check if the line had anything but whitespace and if we
        // have found a shorter prefix
        if whitespace_idx < line.len() && whitespace_idx < prefix.len() {
            prefix = &line[..whitespace_idx];
        }
    }

    // We now go over the lines a second time to build the result.
    let mut result = String::new();
    for line in s.lines() {
        if line.starts_with(prefix) && line.chars().any(|c| !c.is_whitespace()) {
            let (_, tail) = line.split_at(prefix.len());
            result.push_str(tail);
        }
        result.push('\n');
    }

    if result.ends_with('\n') && !s.ends_with('\n') {
        let new_len = result.len() - 1;
        result.truncate(new_len);
    }

    result
}

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

    #[test]
    fn indent_empty() {
        assert_eq!(indent("\n", "  "), "\n");
    }

    #[test]
    #[rustfmt::skip]
    fn indent_nonempty() {
        let text = [
            "  foo\n",
            "bar\n",
            "  baz\n",
        ].join("");
        let expected = [
            "//   foo\n",
            "// bar\n",
            "//   baz\n",
        ].join("");
        assert_eq!(indent(&text, "// "), expected);
    }

    #[test]
    #[rustfmt::skip]
    fn indent_empty_line() {
        let text = [
            "  foo",
            "bar",
            "",
            "  baz",
        ].join("\n");
        let expected = [
            "//   foo",
            "// bar",
            "//",
            "//   baz",
        ].join("\n");
        assert_eq!(indent(&text, "// "), expected);
    }

    #[test]
    fn dedent_empty() {
        assert_eq!(dedent(""), "");
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_multi_line() {
        let x = [
            "    foo",
            "  bar",
            "    baz",
        ].join("\n");
        let y = [
            "  foo",
            "bar",
            "  baz"
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_empty_line() {
        let x = [
            "    foo",
            "  bar",
            "   ",
            "    baz"
        ].join("\n");
        let y = [
            "  foo",
            "bar",
            "",
            "  baz"
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_blank_line() {
        let x = [
            "      foo",
            "",
            "        bar",
            "          foo",
            "          bar",
            "          baz",
        ].join("\n");
        let y = [
            "foo",
            "",
            "  bar",
            "    foo",
            "    bar",
            "    baz",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_whitespace_line() {
        let x = [
            "      foo",
            " ",
            "        bar",
            "          foo",
            "          bar",
            "          baz",
        ].join("\n");
        let y = [
            "foo",
            "",
            "  bar",
            "    foo",
            "    bar",
            "    baz",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_mixed_whitespace() {
        let x = [
            "\tfoo",
            "  bar",
        ].join("\n");
        let y = [
            "\tfoo",
            "  bar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_tabbed_whitespace() {
        let x = [
            "\t\tfoo",
            "\t\t\tbar",
        ].join("\n");
        let y = [
            "foo",
            "\tbar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_mixed_tabbed_whitespace() {
        let x = [
            "\t  \tfoo",
            "\t  \t\tbar",
        ].join("\n");
        let y = [
            "foo",
            "\tbar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_mixed_tabbed_whitespace2() {
        let x = [
            "\t  \tfoo",
            "\t    \tbar",
        ].join("\n");
        let y = [
            "\tfoo",
            "  \tbar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }

    #[test]
    #[rustfmt::skip]
    fn dedent_preserve_no_terminating_newline() {
        let x = [
            "  foo",
            "    bar",
        ].join("\n");
        let y = [
            "foo",
            "  bar",
        ].join("\n");
        assert_eq!(dedent(&x), y);
    }
}
<|endoftext|>


<commit_before>use chan;
use chan::{Sender, Receiver};
use std;
use std::borrow::Cow;

use datatype::{AccessToken, Auth, ClientCredentials, Command, Config, Error, Event,
               Package, UpdateReport, UpdateRequestStatus as Status, UpdateResultCode};
use gateway::Interpret;
use http::{AuthClient, Client};
use oauth2::authenticate;
use package_manager::PackageManager;
use rvi::Services;
use sota::Sota;

/// An `Interpreter` loops over any incoming values, on receipt of which it
/// delegates to the `interpret` function which will respond with output values.
pub trait Interpreter<I, O> {
    fn interpret(&mut self, input: I, otx: &Sender<O>);

    fn run(&mut self, irx: Receiver<I>, otx: Sender<O>) {
        loop {
            self.interpret(irx.recv().expect("interpreter sender closed"), &otx);
        }
    }
}

/// The `EventInterpreter` listens for `Event`s and optionally responds with
/// `Command`s that may be sent to the `CommandInterpreter`.
pub struct EventInterpreter {
    pub package_manager: PackageManager
}

impl Interpreter<Event, Command> for EventInterpreter {
    fn interpret(&mut self, event: Event, ctx: &Sender<Command>) {
        info!("Event received: {}", event);
        match event {
            Event::Authenticated => {
                if self.package_manager != PackageManager::Off {
                    self.package_manager.installed_packages().map(|packages| {
                        ctx.send(Command::SendInstalledPackages(packages));
                    }).unwrap_or_else(|err| error!("couldn't send a list of packages: {}", err));
                }
                ctx.send(Command::SendSystemInfo);
            }

            Event::NotAuthenticated => {
                info!("Trying to authenticate again...");
                ctx.send(Command::Authenticate(None));
            }

            Event::UpdatesReceived(requests) => {
                for request in requests {
                    match (request.status, &self.package_manager) {
                        (Status::Pending, _) => ctx.send(Command::StartDownload(request.requestId.clone())),

                        (Status::InFlight, &PackageManager::Off) => (),

                        (Status::InFlight, _) => {
                            if self.package_manager.is_installed(&request.packageId) {
                                ctx.send(Command::SendUpdateReport(UpdateReport::single(
                                    request.requestId.clone(), UpdateResultCode::OK, "".to_string())));
                            } else {
                                ctx.send(Command::StartDownload(request.requestId.clone()));
                            }
                        }

                        _ => ()
                    }
                }
            }

            Event::DownloadComplete(dl) => {
                if self.package_manager != PackageManager::Off {
                    ctx.send(Command::StartInstall(dl.update_id.clone()));
                }
            }

            Event::DownloadFailed(id, reason) => {
                let report = UpdateReport::single(id, UpdateResultCode::GENERAL_ERROR, reason);
                ctx.send(Command::SendUpdateReport(report));
            }

            Event::InstallComplete(report) | Event::InstallFailed(report) => {
                ctx.send(Command::SendUpdateReport(report));
            }

            Event::UpdateReportSent => {
                if self.package_manager != PackageManager::Off {
                    self.package_manager.installed_packages().map(|packages| {
                        ctx.send(Command::SendInstalledPackages(packages));
                    }).unwrap_or_else(|err| error!("couldn't send a list of packages: {}", err));
                }
            }

            _ => ()
        }
    }
}

/// The `CommandInterpreter` wraps each incoming `Command` inside an `Interpret`
/// type with no response channel for sending to the `GlobalInterpreter`.
pub struct CommandInterpreter;

impl Interpreter<Command, Interpret> for CommandInterpreter {
    fn interpret(&mut self, cmd: Command, itx: &Sender<Interpret>) {
        info!("Command received: {}", cmd);
        itx.send(Interpret { command: cmd, response_tx: None });
    }
}

/// The `GlobalInterpreter` interprets the `Command` inside incoming `Interpret`
/// messages, broadcasting `Event`s globally and (optionally) sending the final
/// outcome `Event` to the `Interpret` response channel.
pub struct GlobalInterpreter<'t> {
    pub config:      Config,
    pub token:       Option<Cow<'t, AccessToken>>,
    pub http_client: Box<Client>,
    pub rvi:         Option<Services>
}

impl<'t> Interpreter<Interpret, Event> for GlobalInterpreter<'t> {
    fn interpret(&mut self, interpret: Interpret, etx: &Sender<Event>) {
        info!("Interpreter started: {}", interpret.command);

        let (multi_tx, multi_rx) = chan::async::<Event>();
        let outcome = match (self.token.as_ref(), self.config.auth.is_none()) {
            (Some(_), _) | (_, true) => self.authenticated(interpret.command, multi_tx),
            _                        => self.unauthenticated(interpret.command, multi_tx)
        };

        let mut response_ev: Option<Event> = None;
        match outcome {
            Ok(_) => {
                for ev in multi_rx {
                    etx.send(ev.clone());
                    response_ev = Some(ev);
                }
            }

            Err(Error::HttpAuth(resp)) => {
                error!("HTTP authorization failed: {}", resp);
                self.token = None;
                let ev = Event::NotAuthenticated;
                etx.send(ev.clone());
                response_ev = Some(ev);
            }

            Err(err) => {
                let ev = Event::Error(format!("{}", err));
                etx.send(ev.clone());
                response_ev = Some(ev);
            }
        }

        info!("Interpreter finished.");
        let ev = response_ev.expect("no response event to send back");
        interpret.response_tx.map(|tx| tx.lock().unwrap().send(ev));
    }
}

impl<'t> GlobalInterpreter<'t> {
    fn authenticated(&self, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
        let mut sota = Sota::new(&self.config, self.http_client.as_ref());

        // always send at least one Event response
        match cmd {
            Command::Authenticate(_) => etx.send(Event::AlreadyAuthenticated),

            Command::GetUpdateRequests => {
                let mut updates = try!(sota.get_update_requests());
                if updates.is_empty() {
                    etx.send(Event::NoUpdateRequests);
                } else {
                    updates.sort_by_key(|u| u.installPos);
                    etx.send(Event::UpdatesReceived(updates));
                }
            }

            Command::ListInstalledPackages => {
                let mut packages: Vec<Package> = Vec::new();
                if self.config.device.package_manager != PackageManager::Off {
                    packages = try!(self.config.device.package_manager.installed_packages());
                }
                etx.send(Event::FoundInstalledPackages(packages));
            }

            Command::ListSystemInfo => {
                let info = try!(self.config.device.system_info.report());
                etx.send(Event::FoundSystemInfo(info));
            }

            Command::SendInstalledPackages(packages) => {
                try!(sota.send_installed_packages(&packages));
                etx.send(Event::InstalledPackagesSent);
            }

            Command::SendInstalledSoftware(sw) => {
                if let Some(ref rvi) = self.rvi {
                    let _ = rvi.remote.lock().unwrap().send_installed_software(sw);
                }
                etx.send(Event::InstalledSoftwareSent);
            }

            Command::SendSystemInfo => {
                let info = try!(self.config.device.system_info.report());
                try!(sota.send_system_info(&info));
                etx.send(Event::SystemInfoSent);
            }

            Command::SendUpdateReport(report) => {
                if let Some(ref rvi) = self.rvi {
                    let _ = rvi.remote.lock().unwrap().send_update_report(report);
                } else {
                    try!(sota.send_update_report(&report));
                }
                etx.send(Event::UpdateReportSent);
            }

            Command::StartDownload(id) => {
                etx.send(Event::DownloadingUpdate(id.clone()));
                if let Some(ref rvi) = self.rvi {
                    let _ = rvi.remote.lock().unwrap().send_download_started(id);
                } else {
                    let _ = sota.download_update(id.clone())
                        .map(|dl| etx.send(Event::DownloadComplete(dl)))
                        .map_err(|err| etx.send(Event::DownloadFailed(id, format!("{}", err))));
                }
            }

            Command::StartInstall(id) => {
                etx.send(Event::InstallingUpdate(id.clone()));
                let _ = sota.install_update(id)
                    .map(|report| etx.send(Event::InstallComplete(report)))
                    .map_err(|report| etx.send(Event::InstallFailed(report)));
            }

            Command::Shutdown => std::process::exit(0),
        }

        Ok(())
    }

    fn unauthenticated(&mut self, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
        match cmd {
            Command::Authenticate(_) => {
                let config = self.config.auth.clone().expect("trying to authenticate without auth config");
                self.set_client(Auth::Credentials(ClientCredentials {
                    client_id:     config.client_id,
                    client_secret: config.client_secret,
                }));
                let server = config.server.join("/token").expect("couldn't build authentication url");
                let token  = try!(authenticate(server, self.http_client.as_ref()));
                self.set_client(Auth::Token(token.clone()));
                self.token = Some(token.into());
                etx.send(Event::Authenticated);
            }

            Command::Shutdown => std::process::exit(0),

            _ => etx.send(Event::NotAuthenticated)
        }

        Ok(())
    }

    fn set_client(&mut self, auth: Auth) {
        if !self.http_client.is_testing() {
            self.http_client = Box::new(AuthClient::from(auth));
        }
    }
}

#[cfg(test)]
mod tests {
    use chan;
    use chan::{Sender, Receiver};
    use std::thread;

    use super::*;
    use datatype::{AccessToken, Command, Config, DownloadComplete, Event,
                   UpdateReport, UpdateResultCode};
    use gateway::Interpret;
    use http::test_client::TestClient;
    use package_manager::PackageManager;
    use package_manager::tpm::assert_rx;

    fn new_interpreter(replies: Vec<String>, pkg_mgr: PackageManager) -> (Sender<Command>, Receiver<Event>) {
        let (etx, erx) = chan::sync::<Event>(0);
        let (ctx, crx) = chan::sync::<Command>(0);

        thread::spawn(move || {
            let mut gi = GlobalInterpreter {
                config:      Config::default(),
                token:       Some(AccessToken::default().into()),
                http_client: Box::new(TestClient::from(replies)),
                rvi:         None
            };
            gi.config.device.package_manager = pkg_mgr;

            loop {
                match crx.recv() {
                    Some(cmd) => gi.interpret(Interpret { command: cmd, response_tx: None }, &etx),
                    None      => break
                }
            }
        });

        (ctx, erx)
    }

    #[test]
    fn already_authenticated() {
        let replies    = Vec::new();
        let pkg_mgr    = PackageManager::new_tpm(true);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::Authenticate(None));
        assert_rx(erx, &[Event::Authenticated]);
    }

    #[test]
    fn download_updates() {
        let replies    = vec!["[]".to_string(); 10];
        let pkg_mgr    = PackageManager::new_tpm(true);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::StartDownload("1".to_string()));
        assert_rx(erx, &[
            Event::DownloadingUpdate("1".to_string()),
            Event::DownloadComplete(DownloadComplete {
                update_id:    "1".to_string(),
                update_image: "/tmp/1".to_string(),
                signature:    "".to_string()
            })
        ]);
    }

    #[test]
    fn install_update_success() {
        let replies    = vec!["[]".to_string(); 10];
        let pkg_mgr    = PackageManager::new_tpm(true);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::StartInstall("1".to_string()));
        assert_rx(erx, &[
            Event::InstallingUpdate("1".to_string()),
            Event::InstallComplete(
                UpdateReport::single("1".to_string(), UpdateResultCode::OK, "".to_string())
            )
        ]);
    }

    #[test]
    fn install_update_failed() {
        let replies    = vec!["[]".to_string(); 10];
        let pkg_mgr    = PackageManager::new_tpm(false);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::StartInstall("1".to_string()));
        assert_rx(erx, &[
            Event::InstallingUpdate("1".to_string()),
            Event::InstallFailed(
                UpdateReport::single("1".to_string(), UpdateResultCode::INSTALL_FAILED, "failed".to_string())
            )
        ]);
    }
}
<commit_msg>Fix AlreadyAuthenticated test<commit_after>use chan;
use chan::{Sender, Receiver};
use std;
use std::borrow::Cow;

use datatype::{AccessToken, Auth, ClientCredentials, Command, Config, Error, Event,
               Package, UpdateReport, UpdateRequestStatus as Status, UpdateResultCode};
use gateway::Interpret;
use http::{AuthClient, Client};
use oauth2::authenticate;
use package_manager::PackageManager;
use rvi::Services;
use sota::Sota;

/// An `Interpreter` loops over any incoming values, on receipt of which it
/// delegates to the `interpret` function which will respond with output values.
pub trait Interpreter<I, O> {
    fn interpret(&mut self, input: I, otx: &Sender<O>);

    fn run(&mut self, irx: Receiver<I>, otx: Sender<O>) {
        loop {
            self.interpret(irx.recv().expect("interpreter sender closed"), &otx);
        }
    }
}

/// The `EventInterpreter` listens for `Event`s and optionally responds with
/// `Command`s that may be sent to the `CommandInterpreter`.
pub struct EventInterpreter {
    pub package_manager: PackageManager
}

impl Interpreter<Event, Command> for EventInterpreter {
    fn interpret(&mut self, event: Event, ctx: &Sender<Command>) {
        info!("Event received: {}", event);
        match event {
            Event::Authenticated => {
                if self.package_manager != PackageManager::Off {
                    self.package_manager.installed_packages().map(|packages| {
                        ctx.send(Command::SendInstalledPackages(packages));
                    }).unwrap_or_else(|err| error!("couldn't send a list of packages: {}", err));
                }
                ctx.send(Command::SendSystemInfo);
            }

            Event::NotAuthenticated => {
                info!("Trying to authenticate again...");
                ctx.send(Command::Authenticate(None));
            }

            Event::UpdatesReceived(requests) => {
                for request in requests {
                    match (request.status, &self.package_manager) {
                        (Status::Pending, _) => ctx.send(Command::StartDownload(request.requestId.clone())),

                        (Status::InFlight, &PackageManager::Off) => (),

                        (Status::InFlight, _) => {
                            if self.package_manager.is_installed(&request.packageId) {
                                ctx.send(Command::SendUpdateReport(UpdateReport::single(
                                    request.requestId.clone(), UpdateResultCode::OK, "".to_string())));
                            } else {
                                ctx.send(Command::StartDownload(request.requestId.clone()));
                            }
                        }

                        _ => ()
                    }
                }
            }

            Event::DownloadComplete(dl) => {
                if self.package_manager != PackageManager::Off {
                    ctx.send(Command::StartInstall(dl.update_id.clone()));
                }
            }

            Event::DownloadFailed(id, reason) => {
                let report = UpdateReport::single(id, UpdateResultCode::GENERAL_ERROR, reason);
                ctx.send(Command::SendUpdateReport(report));
            }

            Event::InstallComplete(report) | Event::InstallFailed(report) => {
                ctx.send(Command::SendUpdateReport(report));
            }

            Event::UpdateReportSent => {
                if self.package_manager != PackageManager::Off {
                    self.package_manager.installed_packages().map(|packages| {
                        ctx.send(Command::SendInstalledPackages(packages));
                    }).unwrap_or_else(|err| error!("couldn't send a list of packages: {}", err));
                }
            }

            _ => ()
        }
    }
}

/// The `CommandInterpreter` wraps each incoming `Command` inside an `Interpret`
/// type with no response channel for sending to the `GlobalInterpreter`.
pub struct CommandInterpreter;

impl Interpreter<Command, Interpret> for CommandInterpreter {
    fn interpret(&mut self, cmd: Command, itx: &Sender<Interpret>) {
        info!("Command received: {}", cmd);
        itx.send(Interpret { command: cmd, response_tx: None });
    }
}

/// The `GlobalInterpreter` interprets the `Command` inside incoming `Interpret`
/// messages, broadcasting `Event`s globally and (optionally) sending the final
/// outcome `Event` to the `Interpret` response channel.
pub struct GlobalInterpreter<'t> {
    pub config:      Config,
    pub token:       Option<Cow<'t, AccessToken>>,
    pub http_client: Box<Client>,
    pub rvi:         Option<Services>
}

impl<'t> Interpreter<Interpret, Event> for GlobalInterpreter<'t> {
    fn interpret(&mut self, interpret: Interpret, etx: &Sender<Event>) {
        info!("Interpreter started: {}", interpret.command);

        let (multi_tx, multi_rx) = chan::async::<Event>();
        let outcome = match (self.token.as_ref(), self.config.auth.is_none()) {
            (Some(_), _) | (_, true) => self.authenticated(interpret.command, multi_tx),
            _                        => self.unauthenticated(interpret.command, multi_tx)
        };

        let mut response_ev: Option<Event> = None;
        match outcome {
            Ok(_) => {
                for ev in multi_rx {
                    etx.send(ev.clone());
                    response_ev = Some(ev);
                }
            }

            Err(Error::HttpAuth(resp)) => {
                error!("HTTP authorization failed: {}", resp);
                self.token = None;
                let ev = Event::NotAuthenticated;
                etx.send(ev.clone());
                response_ev = Some(ev);
            }

            Err(err) => {
                let ev = Event::Error(format!("{}", err));
                etx.send(ev.clone());
                response_ev = Some(ev);
            }
        }

        info!("Interpreter finished.");
        let ev = response_ev.expect("no response event to send back");
        interpret.response_tx.map(|tx| tx.lock().unwrap().send(ev));
    }
}

impl<'t> GlobalInterpreter<'t> {
    fn authenticated(&self, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
        let mut sota = Sota::new(&self.config, self.http_client.as_ref());

        // always send at least one Event response
        match cmd {
            Command::Authenticate(_) => etx.send(Event::AlreadyAuthenticated),

            Command::GetUpdateRequests => {
                let mut updates = try!(sota.get_update_requests());
                if updates.is_empty() {
                    etx.send(Event::NoUpdateRequests);
                } else {
                    updates.sort_by_key(|u| u.installPos);
                    etx.send(Event::UpdatesReceived(updates));
                }
            }

            Command::ListInstalledPackages => {
                let mut packages: Vec<Package> = Vec::new();
                if self.config.device.package_manager != PackageManager::Off {
                    packages = try!(self.config.device.package_manager.installed_packages());
                }
                etx.send(Event::FoundInstalledPackages(packages));
            }

            Command::ListSystemInfo => {
                let info = try!(self.config.device.system_info.report());
                etx.send(Event::FoundSystemInfo(info));
            }

            Command::SendInstalledPackages(packages) => {
                try!(sota.send_installed_packages(&packages));
                etx.send(Event::InstalledPackagesSent);
            }

            Command::SendInstalledSoftware(sw) => {
                if let Some(ref rvi) = self.rvi {
                    let _ = rvi.remote.lock().unwrap().send_installed_software(sw);
                }
                etx.send(Event::InstalledSoftwareSent);
            }

            Command::SendSystemInfo => {
                let info = try!(self.config.device.system_info.report());
                try!(sota.send_system_info(&info));
                etx.send(Event::SystemInfoSent);
            }

            Command::SendUpdateReport(report) => {
                if let Some(ref rvi) = self.rvi {
                    let _ = rvi.remote.lock().unwrap().send_update_report(report);
                } else {
                    try!(sota.send_update_report(&report));
                }
                etx.send(Event::UpdateReportSent);
            }

            Command::StartDownload(id) => {
                etx.send(Event::DownloadingUpdate(id.clone()));
                if let Some(ref rvi) = self.rvi {
                    let _ = rvi.remote.lock().unwrap().send_download_started(id);
                } else {
                    let _ = sota.download_update(id.clone())
                        .map(|dl| etx.send(Event::DownloadComplete(dl)))
                        .map_err(|err| etx.send(Event::DownloadFailed(id, format!("{}", err))));
                }
            }

            Command::StartInstall(id) => {
                etx.send(Event::InstallingUpdate(id.clone()));
                let _ = sota.install_update(id)
                    .map(|report| etx.send(Event::InstallComplete(report)))
                    .map_err(|report| etx.send(Event::InstallFailed(report)));
            }

            Command::Shutdown => std::process::exit(0),
        }

        Ok(())
    }

    fn unauthenticated(&mut self, cmd: Command, etx: Sender<Event>) -> Result<(), Error> {
        match cmd {
            Command::Authenticate(_) => {
                let config = self.config.auth.clone().expect("trying to authenticate without auth config");
                self.set_client(Auth::Credentials(ClientCredentials {
                    client_id:     config.client_id,
                    client_secret: config.client_secret,
                }));
                let server = config.server.join("/token").expect("couldn't build authentication url");
                let token  = try!(authenticate(server, self.http_client.as_ref()));
                self.set_client(Auth::Token(token.clone()));
                self.token = Some(token.into());
                etx.send(Event::Authenticated);
            }

            Command::Shutdown => std::process::exit(0),

            _ => etx.send(Event::NotAuthenticated)
        }

        Ok(())
    }

    fn set_client(&mut self, auth: Auth) {
        if !self.http_client.is_testing() {
            self.http_client = Box::new(AuthClient::from(auth));
        }
    }
}

#[cfg(test)]
mod tests {
    use chan;
    use chan::{Sender, Receiver};
    use std::thread;

    use super::*;
    use datatype::{AccessToken, Command, Config, DownloadComplete, Event,
                   UpdateReport, UpdateResultCode};
    use gateway::Interpret;
    use http::test_client::TestClient;
    use package_manager::PackageManager;
    use package_manager::tpm::assert_rx;

    fn new_interpreter(replies: Vec<String>, pkg_mgr: PackageManager) -> (Sender<Command>, Receiver<Event>) {
        let (etx, erx) = chan::sync::<Event>(0);
        let (ctx, crx) = chan::sync::<Command>(0);

        thread::spawn(move || {
            let mut gi = GlobalInterpreter {
                config:      Config::default(),
                token:       Some(AccessToken::default().into()),
                http_client: Box::new(TestClient::from(replies)),
                rvi:         None
            };
            gi.config.device.package_manager = pkg_mgr;

            loop {
                match crx.recv() {
                    Some(cmd) => gi.interpret(Interpret { command: cmd, response_tx: None }, &etx),
                    None      => break
                }
            }
        });

        (ctx, erx)
    }

    #[test]
    fn already_authenticated() {
        let replies    = Vec::new();
        let pkg_mgr    = PackageManager::new_tpm(true);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::Authenticate(None));
        assert_rx(erx, &[Event::AlreadyAuthenticated]);
    }

    #[test]
    fn download_updates() {
        let replies    = vec!["[]".to_string(); 10];
        let pkg_mgr    = PackageManager::new_tpm(true);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::StartDownload("1".to_string()));
        assert_rx(erx, &[
            Event::DownloadingUpdate("1".to_string()),
            Event::DownloadComplete(DownloadComplete {
                update_id:    "1".to_string(),
                update_image: "/tmp/1".to_string(),
                signature:    "".to_string()
            })
        ]);
    }

    #[test]
    fn install_update_success() {
        let replies    = vec!["[]".to_string(); 10];
        let pkg_mgr    = PackageManager::new_tpm(true);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::StartInstall("1".to_string()));
        assert_rx(erx, &[
            Event::InstallingUpdate("1".to_string()),
            Event::InstallComplete(
                UpdateReport::single("1".to_string(), UpdateResultCode::OK, "".to_string())
            )
        ]);
    }

    #[test]
    fn install_update_failed() {
        let replies    = vec!["[]".to_string(); 10];
        let pkg_mgr    = PackageManager::new_tpm(false);
        let (ctx, erx) = new_interpreter(replies, pkg_mgr);

        ctx.send(Command::StartInstall("1".to_string()));
        assert_rx(erx, &[
            Event::InstallingUpdate("1".to_string()),
            Event::InstallFailed(
                UpdateReport::single("1".to_string(), UpdateResultCode::INSTALL_FAILED, "failed".to_string())
            )
        ]);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::CString;
use std::path::PathBuf;
use std::process::{Command, exit, Stdio};
use std::time::Instant;

use crate::argument::Argument;
use crate::core::*;

const TMUX: &str = "tmux";

pub struct Tmux<'a> {
    nmk_dir: &'a PathBuf,
    tmux_dir: PathBuf,
    bin: String,
    version: String,
}

impl<'a> Tmux<'a> {
    pub fn new(nmk_dir: &PathBuf, tmux_dir: PathBuf) -> Tmux {
        Tmux {
            nmk_dir,
            tmux_dir,
            bin: which::which(TMUX).unwrap().to_str().unwrap().to_string(),
            version: Tmux::call_check_version(),
        }
    }

    pub fn version(&self) -> &str {
        &self.version
    }

    fn conf(&self) -> PathBuf {
        let conf_file = format!("{}.conf", &self.version);
        let conf_path = self.tmux_dir.join(conf_file);
        if !conf_path.exists() {
            error!("tmux {} is not supported", &self.version)
        }
        conf_path
    }

    pub fn setup(&self, arg: &Argument) {
        set_env("NMK_TMUX_DEFAULT_SHELL", which::which("zsh").expect("zsh not found"));
        set_env("NMK_TMUX_DETACH_ON_DESTROY", on_off!(arg.detach_on_destroy));
        set_env("NMK_TMUX_HISTORY", self.nmk_dir.join("tmux").join(".tmux_history"));
        set_env("NMK_TMUX_VERSION", &self.version);
    }

    fn print_usage_time(&self, arg: &Argument, start: &Instant) {
        let before_exec = start.elapsed().as_millis();
        if arg.usage {
            println!("{}", before_exec);
        } else {
            debug!("usage time: {}ms", before_exec);
        }
    }

    fn call_check_version() -> String {
        if let Ok(o) = Command::new(TMUX).arg("-V").output() {
            if !o.status.success() {
                match o.status.code() {
                    Some(i) => error!("tmux exit with status: {}", i),
                    None => error!("terminated by signal"),
                };
                exit(1);
            }
            let version_output = String::from_utf8(o.stdout)
                .expect("tmux version output contain non utf-8");
            version_output.trim().split(" ")
                .nth(1).expect(&format!("bad output: {}", version_output))
                .to_string()
        } else {
            error!("{} not found", TMUX);
            exit(1);
        }
    }

    pub fn login_shell(&self, arg: Argument, start: Instant) -> ! {
        let mut vec = Vec::new();

        vec.push(self.bin.as_str());
        vec.push("-L");
        vec.push(arg.socket());
        if arg.force256color {
            vec.push("-2");
        }
        vec.push("-f");
        let config = self.conf();
        vec.push(config.to_str().unwrap());
        vec.push("-c");
        vec.push("exec zsh --login");
        let exec_args: Vec<_> = vec.into_iter().flat_map(CString::new).collect();
        let exec_name = CString::new(self.bin.as_bytes()).unwrap();
        debug!("{:#?}", exec_name);
        debug!("{:#?}", exec_args);
        self.print_usage_time(&arg, &start);
        if nix::unistd::execvp(&exec_name, &exec_args).is_err() {
            error!("Can't start login shell")
        }
        // this code is never reach if exec success
        exit(1);
    }

    pub fn exec(&self, arg: Argument, start: Instant) -> ! {
        let mut vec = Vec::new();
        let config = self.conf();
        vec.push(self.bin.as_str());
        vec.push("-L");
        let socket = arg.socket();
        vec.push(socket);
        if arg.force256color {
            vec.push("-2");
        }
        let tmux_args = arg.tmux_args();
        if is_running(socket) {
            if tmux_args.len() > 0 {
                vec.extend(tmux_args);
            } else {
                if env::var_os("TMUX").is_some() && !arg.inception {
                    warn!("add --inception to allow nested tmux sessions");
                    exit(1);
                }
                vec.push("attach");
            }
        } else {
            vec.push("-f");
            vec.push(config.to_str().unwrap());
            vec.extend(tmux_args);
        }
        let exec_args: Vec<_> = vec.into_iter().flat_map(CString::new).collect();
        let exec_name = CString::new(self.bin.as_bytes()).unwrap();
        debug!("{:#?}", exec_name);
        debug!("{:#?}", exec_args);
        self.print_usage_time(&arg, &start);
        if nix::unistd::execvp(&exec_name, &exec_args).is_err() {
            error!("Can't start tmux")
        }
        // this code is never reach if exec success
        exit(1);
    }
}

pub fn is_running(socket: &str) -> bool {
    let running = Command::new(TMUX)
        .arg("-L")
        .arg(socket)
        .arg("list-sessions")
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
        .map(|o| o.success())
        .unwrap_or_default();
    debug!("server {} running", if running { "is" } else { "is not" });
    running
}

pub fn dir(nmk_dir: &PathBuf) -> PathBuf {
    let path = nmk_dir.join("tmux");
    if !path.exists() {
        panic!("{:?} doesn't exist", path);
    }
    path
}
<commit_msg>nmk.rs: call exec correctly<commit_after>use std::env;
use std::ffi::CString;
use std::path::PathBuf;
use std::process::{Command, exit, Stdio};
use std::time::Instant;

use crate::argument::Argument;
use crate::core::*;

const TMUX: &str = "tmux";

pub struct Tmux<'a> {
    nmk_dir: &'a PathBuf,
    tmux_dir: PathBuf,
    bin: String,
    version: String,
}

impl<'a> Tmux<'a> {
    pub fn new(nmk_dir: &PathBuf, tmux_dir: PathBuf) -> Tmux {
        Tmux {
            nmk_dir,
            tmux_dir,
            bin: which::which(TMUX).unwrap().to_str().unwrap().to_string(),
            version: Tmux::call_check_version(),
        }
    }

    pub fn version(&self) -> &str {
        &self.version
    }

    fn conf(&self) -> PathBuf {
        let conf_file = format!("{}.conf", &self.version);
        let conf_path = self.tmux_dir.join(conf_file);
        if !conf_path.exists() {
            error!("tmux {} is not supported", &self.version)
        }
        conf_path
    }

    pub fn setup(&self, arg: &Argument) {
        set_env("NMK_TMUX_DEFAULT_SHELL", which::which("zsh").expect("zsh not found"));
        set_env("NMK_TMUX_DETACH_ON_DESTROY", on_off!(arg.detach_on_destroy));
        set_env("NMK_TMUX_HISTORY", self.nmk_dir.join("tmux").join(".tmux_history"));
        set_env("NMK_TMUX_VERSION", &self.version);
    }

    fn print_usage_time(&self, arg: &Argument, start: &Instant) {
        let before_exec = start.elapsed().as_millis();
        if arg.usage {
            println!("{}", before_exec);
        } else {
            debug!("usage time: {}ms", before_exec);
        }
    }

    fn call_check_version() -> String {
        if let Ok(o) = Command::new(TMUX).arg("-V").output() {
            if !o.status.success() {
                match o.status.code() {
                    Some(i) => error!("tmux exit with status: {}", i),
                    None => error!("terminated by signal"),
                };
                exit(1);
            }
            let version_output = String::from_utf8(o.stdout)
                .expect("tmux version output contain non utf-8");
            version_output.trim().split(" ")
                .nth(1).expect(&format!("bad output: {}", version_output))
                .to_string()
        } else {
            error!("{} not found", TMUX);
            exit(1);
        }
    }

    pub fn login_shell(&self, arg: Argument, start: Instant) -> ! {
        let mut vec = Vec::new();

        vec.push(TMUX);
        vec.push("-L");
        vec.push(arg.socket());
        if arg.force256color {
            vec.push("-2");
        }
        vec.push("-f");
        let config = self.conf();
        vec.push(config.to_str().unwrap());
        vec.push("-c");
        vec.push("exec zsh --login");
        let exec_args: Vec<_> = vec.into_iter().flat_map(CString::new).collect();
        let exec_name = CString::new(self.bin.as_bytes()).unwrap();
        debug!("{:#?}", exec_name);
        debug!("{:#?}", exec_args);
        self.print_usage_time(&arg, &start);
        if nix::unistd::execv(&exec_name, &exec_args).is_err() {
            error!("Can't start login shell")
        }
        // this code is never reach if exec success
        exit(1);
    }

    pub fn exec(&self, arg: Argument, start: Instant) -> ! {
        let mut vec = Vec::new();
        let config = self.conf();
        vec.push(TMUX);
        vec.push("-L");
        let socket = arg.socket();
        vec.push(socket);
        if arg.force256color {
            vec.push("-2");
        }
        let tmux_args = arg.tmux_args();
        if is_running(socket) {
            if tmux_args.len() > 0 {
                vec.extend(tmux_args);
            } else {
                if env::var_os("TMUX").is_some() && !arg.inception {
                    warn!("add --inception to allow nested tmux sessions");
                    exit(1);
                }
                vec.push("attach");
            }
        } else {
            vec.push("-f");
            vec.push(config.to_str().unwrap());
            vec.extend(tmux_args);
        }
        let exec_args: Vec<_> = vec.into_iter().flat_map(CString::new).collect();
        let exec_name = CString::new(self.bin.as_bytes()).unwrap();
        debug!("{:#?}", exec_name);
        debug!("{:#?}", exec_args);
        self.print_usage_time(&arg, &start);
        if nix::unistd::execv(&exec_name, &exec_args).is_err() {
            error!("Can't start tmux")
        }
        // this code is never reach if exec success
        exit(1);
    }
}

pub fn is_running(socket: &str) -> bool {
    let running = Command::new(TMUX)
        .arg("-L")
        .arg(socket)
        .arg("list-sessions")
        .stderr(Stdio::null())
        .stdout(Stdio::null())
        .status()
        .map(|o| o.success())
        .unwrap_or_default();
    debug!("server {} running", if running { "is" } else { "is not" });
    running
}

pub fn dir(nmk_dir: &PathBuf) -> PathBuf {
    let path = nmk_dir.join("tmux");
    if !path.exists() {
        panic!("{:?} doesn't exist", path);
    }
    path
}
<|endoftext|>


<commit_before>pub mod operation {
    #[derive(Debug)]
    enum OperationSource {
        UNKNOWN(String),
        SOAP,
        REST,
        WEBSITE,
        BATCH
    }

    impl OperationSource {
        fn from_str(data: &str) -> OperationSource {
            match data {
                "SOAP" => OperationSource::SOAP,
                "REST" => OperationSource::REST,
                "WEBSITE" => OperationSource::WEBSITE,
                "BATCH" => OperationSource::BATCH,
                _ => OperationSource::UNKNOWN(data.to_string())
            }
        }
    }

    #[derive(Debug)]
    enum OperationMethod {
        UNKNOWN(String),
        GET,
        PUT,
        DELETE
    }

    impl OperationMethod {
        fn from_str(data: &str) -> OperationMethod {
            match data {
                "GET" => OperationMethod::GET,
                "PUT" => OperationMethod::PUT,
                "DELETE" => OperationMethod::DELETE,
                _ => OperationMethod::UNKNOWN(data.to_string())
            }
        }
    }

    #[derive(Debug)]
    enum OperationResourceType {
        UNKNOWN(String),
        OBJECT
    }

    impl OperationResourceType {
        fn from_str(data: &str) -> OperationResourceType {
            match data {
                "OBJECT" => OperationResourceType::OBJECT,
                _ => OperationResourceType::UNKNOWN(data.to_string())
            }
        }
    }

    #[derive(Debug)]
    pub struct Operation {
        source: OperationSource,
        method: OperationMethod,
        resource_type: OperationResourceType
    }

    impl Operation {
        pub fn from_str(data: &str) -> Result<Operation, &str> {
            let mut parts = data.split(".");
            let source_option = parts.next();
            let method_option = parts.next();
            let resource_type_option = parts.next();

            let source = match source_option {
                Some(s) => s,
                None => return Err("Unable to find source")
            };

            let method = match method_option {
                Some(s) => s,
                None => return Err("Unable to find match")
            };

            let resource_type = match resource_type_option {
                Some(s) => s,
                None => return Err("Unable to find resource type")
            };

            Ok(Operation {
                source: OperationSource::from_str(source),
                method: OperationMethod::from_str(method),
                resource_type: OperationResourceType::from_str(resource_type)
            })
        }
    }
}
<commit_msg>Making Operation FromStr compliant<commit_after>pub mod operation {
    use std::str::FromStr;

    #[derive(Debug)]
    enum OperationSource {
        UNKNOWN(String),
        SOAP,
        REST,
        WEBSITE,
        BATCH
    }

    impl OperationSource {
        fn from_str(data: &str) -> OperationSource {
            match data {
                "SOAP" => OperationSource::SOAP,
                "REST" => OperationSource::REST,
                "WEBSITE" => OperationSource::WEBSITE,
                "BATCH" => OperationSource::BATCH,
                _ => OperationSource::UNKNOWN(data.to_string())
            }
        }
    }

    #[derive(Debug)]
    enum OperationMethod {
        UNKNOWN(String),
        GET,
        PUT,
        DELETE
    }

    impl OperationMethod {
        fn from_str(data: &str) -> OperationMethod {
            match data {
                "GET" => OperationMethod::GET,
                "PUT" => OperationMethod::PUT,
                "DELETE" => OperationMethod::DELETE,
                _ => OperationMethod::UNKNOWN(data.to_string())
            }
        }
    }

    #[derive(Debug)]
    enum OperationResourceType {
        UNKNOWN(String),
        OBJECT
    }

    impl OperationResourceType {
        fn from_str(data: &str) -> OperationResourceType {
            match data {
                "OBJECT" => OperationResourceType::OBJECT,
                _ => OperationResourceType::UNKNOWN(data.to_string())
            }
        }
    }

    #[derive(Debug)]
    pub struct Operation {
        source: OperationSource,
        method: OperationMethod,
        resource_type: OperationResourceType
    }

    impl FromStr for Operation {
        type Err = &'static str;

        fn from_str(data: &str) -> Result<Operation, &'static str> {
            let mut parts = data.split(".");
            let source_option = parts.next();
            let method_option = parts.next();
            let resource_type_option = parts.next();

            let source = match source_option {
                Some(s) => s,
                None => return Err("Unable to find source")
            };

            let method = match method_option {
                Some(s) => s,
                None => return Err("Unable to find match")
            };

            let resource_type = match resource_type_option {
                Some(s) => s,
                None => return Err("Unable to find resource type")
            };

            Ok(Operation {
                source: OperationSource::from_str(source),
                method: OperationMethod::from_str(method),
                resource_type: OperationResourceType::from_str(resource_type)
            })
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    loop {
        println!("Hello, world!");
        break;
    }

    let mut number = 3;
    while number != 0 {
        println!("{}", number);
        number = number - 1;
    }

    println!("LIFTOFF!!!");

    let a = [10, 20, 30, 40, 50];
    // both safety & no overhead compare to maintain index of
    // array by while
    for element in a.iter() {
        println!("the value is {}", element);
    }

    // for is most commonly used, replace while:
    for count in (1..4).rev() {
        println!("{}!", count);
    }
    println!("LIFTOFF!!!");

    for n in 1..10 {
        println!("fib {} is {}", n, fib(n));
    }
}

fn fib(n: i32) -> i32 {
    let mut cur = 1;
    let mut nxt = 1;
    let mut res = 0;

    for i in 0..n {
        res = cur;
        cur = nxt;
        nxt = res + nxt;
    }

    res
}
<commit_msg>Get rid of compile warning on loop.<commit_after>fn main() {
    loop {
        println!("Hello, world!");
        break;
    }

    let mut number = 3;
    while number != 0 {
        println!("{}", number);
        number = number - 1;
    }

    println!("LIFTOFF!!!");

    let a = [10, 20, 30, 40, 50];
    // both safety & no overhead compare to maintain index of
    // array by while
    for element in a.iter() {
        println!("the value is {}", element);
    }

    // for is most commonly used, replace while:
    for count in (1..4).rev() {
        println!("{}!", count);
    }
    println!("LIFTOFF!!!");

    for n in 1..10 {
        println!("fib {} is {}", n, fib(n));
    }
}

fn fib(n: i32) -> i32 {
    let mut cur = 1;
    let mut nxt = 1;
    let mut res = 0;

    for _ in 0..n {
        res = cur;
        cur = nxt;
        nxt = res + nxt;
    }

    res
}
<|endoftext|>


<commit_before>
extern crate curl;
use curl::easy::Easy;
use std::io::{stdout, Write};

fn main() {
    let mut handle = Easy::new();
    handle.url("https://www.rust-lang.org/").unwrap();
    handle.write_function(|data| {
    Ok(stdout().write(data).unwrap())
        }).unwrap();
    handle.perform().unwrap();
}
<commit_msg>added comments<commit_after>extern crate curl; //Curl crate
use curl::easy::Easy; //Using easy functions
use std::io::{stdout, Write};

fn main() {
    let mut handle = Easy::new();
    handle.url("https://www.rust-lang.org/").unwrap();
    handle.write_function(|data| {
    Ok(stdout().write(data).unwrap())
        }).unwrap();
    handle.perform().unwrap();
}
<|endoftext|>


<commit_before>#![ allow (unused_parens) ]

use futures;
use futures::BoxFuture;
use futures::Future;

use futures_cpupool::CpuPool;

use lru_cache::LruCache;

use minilzo;

use std::error::Error;
use std::io::Read;
use std::io::Write;
use std::fs;
use std::fs::File;
use std::ops::Deref;
use std::ops::DerefMut;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;

#[ derive (Clone) ]
pub struct StorageManager {
	data: Arc <StorageManagerData>,
	state: Arc <Mutex <StorageManagerState>>,
	cpu_pool: CpuPool,
}

#[ derive (Clone) ]
struct StorageManagerData {
	path: String,
}

enum MemoryCacheItem {
	Compressed (Arc <Vec <u8>>, usize),
	Uncompressed (Arc <Vec <u8>>),
}

struct StorageManagerState {
	uncompressed_memory_items: LruCache <String, Arc <Vec <u8>>>,
	compressed_memory_items: LruCache <String, MemoryCacheItem>,
	filesystem_items: LruCache <String, FilesystemItem>,
}

struct FilesystemItem {
	storage_manager: Arc <StorageManagerData>,
	key: String,
	compressed: bool,
	uncompressed_size: usize,
}

impl StorageManager {

	pub fn new <PathRef: AsRef <Path>> (
		path_ref: PathRef,
		cpu_pool: CpuPool,
		uncompressed_memory_cache_size: usize,
		compressed_memory_cache_size: usize,
		filesystem_cache_size: usize,
	) -> Result <StorageManager, String> {

		let path =
			try! (

			path_ref.as_ref ().to_str (
			).ok_or_else (
				||

				format! (
					"Invalid path: {}",
					path_ref.as_ref ().to_string_lossy ())

			)

		).to_owned ();

		let metadata =
			try! (

			fs::metadata (
				& path,
			).map_err (
				|_|

				format! (
					"Unable to access {}",
					& path)

			)

		);

		if ! metadata.is_dir () {

			return Err (
				format! (
					"Not a directory: {}",
					& path));

		}

		// TODO create a test file to check permissions

		Ok (StorageManager {

			data: Arc::new (
				StorageManagerData {

				path:
					path,

			}),

			state: Arc::new (
				Mutex::new (
					StorageManagerState {

				uncompressed_memory_items:
					LruCache::new (
						uncompressed_memory_cache_size),

				compressed_memory_items:
					LruCache::new (
						compressed_memory_cache_size),

				filesystem_items:
					LruCache::new (
						filesystem_cache_size),

			})),

			cpu_pool:
				cpu_pool,

		})

	}

	pub fn insert (
		& mut self,
		key: String,
		uncompressed_data: Arc <Vec <u8>>,
	) -> Result <(), String> {

		let entry_path =
			format! (
				"{}/{}",
				self.data.path,
				key);

		let mut self_state =
			self.state.lock ().unwrap ();

		// store in memory cache

		self_state.uncompressed_memory_items.insert (
			key.deref ().to_owned (),
			uncompressed_data.clone ());

		// try and compress the data

		let (compressed, stored_data) =
			match (

			minilzo::compress (
				& uncompressed_data)

		) {

			Ok (compressed_data) =>
				(true, Arc::new (compressed_data)),

			Err (minilzo::Error::NotCompressible) =>
				(false, uncompressed_data.clone ()),

			Err (error) =>
				return Err (
					format! (
						"Error during compression: {:?}",
						error)),

		};

		// store in compressed memory cache

		self_state.compressed_memory_items.insert (
			key.deref ().to_owned (),
			if compressed {

				MemoryCacheItem::Compressed (
					stored_data.clone (),
					uncompressed_data.len ())

			} else {

				MemoryCacheItem::Uncompressed (
					stored_data.clone ())

			}
		);

		// write out to the filesystem

		let mut output =
			try! (

			File::create (
				& entry_path,
			).map_err (
				|error|

				format! (
					"Unable to create {}: {}",
					& entry_path,
					error.description ())
			)

		);

		try! (

			output.write (
				& stored_data,
			).map_err (
				|error|

				format! (
					"Error writing to {}: {}",
					entry_path,
					error.description ())
			)

		);

		// create and store the filesystem item in the index

		let filesystem_item =
			FilesystemItem {

			storage_manager: self.data.clone (),
			key: key.deref ().to_owned (),
			compressed: compressed,
			uncompressed_size: uncompressed_data.len (),

		};

		self_state.filesystem_items.insert (
			key.deref ().to_owned (),
			filesystem_item);

		Ok (())

	}

	pub fn get (
		& self,
		key: & str,
	) -> Option <BoxFuture <Arc <Vec <u8>>, String>> {

		let mut self_state =
			self.state.lock ().unwrap ();

		// try in uncompressed memory cache

		match (

			self_state.uncompressed_memory_items.get_mut (
				key,
			)

		) {

			Some (item_data) =>
{
stderr! ("-");
				return Some (
					futures::done (
						Ok (item_data.clone ())
					).boxed (),
//				),
)},

			None =>
				(),
		};

		// try in compressed memory cache

		match (

			self_state.compressed_memory_items.get_mut (
				key,
			)

		) {

			Some (
				& mut MemoryCacheItem::Compressed (
					ref compressed_data,
					uncompressed_size)
			) =>
{
stderr! ("x");
				return Some ({

				futures::done (

					minilzo::decompress (
						& compressed_data,
						uncompressed_size,
					).map (
						|uncompressed_data|

						Arc::new (
							uncompressed_data)

					).map_err (
						|error|

						format! (
							"Decompression failed: {:?}",
							error)

					)

				).boxed ()

//			}),
})},

			Some (
				& mut MemoryCacheItem::Uncompressed (
					ref uncompressed_data)
			) =>
				return Some (
					futures::done (
						Ok (uncompressed_data.clone ())
					).boxed (),
				),

			None =>
				(),

		};

		// try in compressed filesystem cache

		Self::get_filesystem (
			self_state.deref_mut (),
			key)

	}

	fn get_filesystem (
		self_state: & mut StorageManagerState,
		key: & str,
	) -> Option <BoxFuture <Arc <Vec <u8>>, String>> {

stderr! ("O");

		match (

			self_state.filesystem_items.get_mut (
				key,
			)

		) {

			Some (filesystem_item) => {

				let uncompressed_data =
					match (

					filesystem_item.get ()

				) {

					Ok (data) =>
						data,

					Err (error) =>
						return Some (
							futures::failed (
								error,
							).boxed ()
						),

				};

				self_state.uncompressed_memory_items.insert (
					key.to_owned (),
					uncompressed_data.clone ());

				Some (futures::done (
					Ok (uncompressed_data)
				).boxed ())

			},

			None =>
				None,

		}

	}

}

impl FilesystemItem {

	fn path (
		& self,
	) -> String {

		format! (
			"{}/{}",
			self.storage_manager.path,
			self.key)

	}

	fn get (
		& self,
	) -> Result <Arc <Vec <u8>>, String> {

		let mut file =
			try! (

			File::open (
				self.path (),
			).map_err (
				|error|

				format! (
					"Error loading storage item {}: {}",
					self.key,
					error.description ())

			)

		);

		let mut stored_data =
			Vec::new ();

		try! (

			file.read_to_end (
				& mut stored_data,
			).map_err (
				|error|

				format! (
					"Error loading storage item {}: {}",
					self.key,
					error.description ())

			)

		);

		if self.compressed {

			let uncompressed_data =
				Arc::new (
					try! (

				minilzo::decompress (
					& stored_data,
					self.uncompressed_size,
				).map_err (
					|error|

					format! (
						"Error decompressing stored data: {:?}",
						error)

				)

			));

			Ok (
				uncompressed_data
			)

		} else {

			Ok (

				Arc::new (
					stored_data)

			)

		}

	}

}

impl Drop for FilesystemItem {

	fn drop (
		& mut self,
	) {

		match (

			fs::remove_file (
				self.path (),
			)

		) {

			Ok (_) => (),

			Err (error) => {

				stderrln! (
					"Error removing storage item {}: {}",
					self.key,
					error.description ());

			}

		}

	}

}

// ex: noet ts=4 filetype=rust
<commit_msg>try create temporary storage directory if it does not already exist<commit_after>#![ allow (unused_parens) ]

use futures;
use futures::BoxFuture;
use futures::Future;

use futures_cpupool::CpuPool;

use lru_cache::LruCache;

use minilzo;

use std::error::Error;
use std::io::Read;
use std::io::Write;
use std::fs;
use std::fs::File;
use std::ops::Deref;
use std::ops::DerefMut;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;

#[ derive (Clone) ]
pub struct StorageManager {
	data: Arc <StorageManagerData>,
	state: Arc <Mutex <StorageManagerState>>,
	cpu_pool: CpuPool,
}

#[ derive (Clone) ]
struct StorageManagerData {
	path: String,
}

enum MemoryCacheItem {
	Compressed (Arc <Vec <u8>>, usize),
	Uncompressed (Arc <Vec <u8>>),
}

struct StorageManagerState {
	uncompressed_memory_items: LruCache <String, Arc <Vec <u8>>>,
	compressed_memory_items: LruCache <String, MemoryCacheItem>,
	filesystem_items: LruCache <String, FilesystemItem>,
}

struct FilesystemItem {
	storage_manager: Arc <StorageManagerData>,
	key: String,
	compressed: bool,
	uncompressed_size: usize,
}

impl StorageManager {

	pub fn new <PathRef: AsRef <Path>> (
		path_ref: PathRef,
		cpu_pool: CpuPool,
		uncompressed_memory_cache_size: usize,
		compressed_memory_cache_size: usize,
		filesystem_cache_size: usize,
	) -> Result <StorageManager, String> {

		// get string from path

		let path =
			try! (

			path_ref.as_ref ().to_str (
			).ok_or_else (
				||

				format! (
					"Invalid path: {}",
					path_ref.as_ref ().to_string_lossy ())

			)

		).to_owned ();

		// try and create filesystem cache path

		try! (

			fs::create_dir_all (
				& path,
			).map_err (
				|error|

				format! (
					"Error creating filesystem cache path: {}: {}",
					& path,
					error.description ())

			)

		);

		// check we can access filesystem cache path

		let metadata =
			try! (

			fs::metadata (
				& path,
			).map_err (
				|_|

				format! (
					"Unable to access {}",
					& path)

			)

		);

		if ! metadata.is_dir () {

			return Err (
				format! (
					"Not a directory: {}",
					& path));

		}

		// TODO create a test file to check permissions

		Ok (StorageManager {

			data: Arc::new (
				StorageManagerData {

				path:
					path,

			}),

			state: Arc::new (
				Mutex::new (
					StorageManagerState {

				uncompressed_memory_items:
					LruCache::new (
						uncompressed_memory_cache_size),

				compressed_memory_items:
					LruCache::new (
						compressed_memory_cache_size),

				filesystem_items:
					LruCache::new (
						filesystem_cache_size),

			})),

			cpu_pool:
				cpu_pool,

		})

	}

	pub fn insert (
		& mut self,
		key: String,
		uncompressed_data: Arc <Vec <u8>>,
	) -> Result <(), String> {

		let entry_path =
			format! (
				"{}/{}",
				self.data.path,
				key);

		let mut self_state =
			self.state.lock ().unwrap ();

		// store in memory cache

		self_state.uncompressed_memory_items.insert (
			key.deref ().to_owned (),
			uncompressed_data.clone ());

		// try and compress the data

		let (compressed, stored_data) =
			match (

			minilzo::compress (
				& uncompressed_data)

		) {

			Ok (compressed_data) =>
				(true, Arc::new (compressed_data)),

			Err (minilzo::Error::NotCompressible) =>
				(false, uncompressed_data.clone ()),

			Err (error) =>
				return Err (
					format! (
						"Error during compression: {:?}",
						error)),

		};

		// store in compressed memory cache

		self_state.compressed_memory_items.insert (
			key.deref ().to_owned (),
			if compressed {

				MemoryCacheItem::Compressed (
					stored_data.clone (),
					uncompressed_data.len ())

			} else {

				MemoryCacheItem::Uncompressed (
					stored_data.clone ())

			}
		);

		// write out to the filesystem

		let mut output =
			try! (

			File::create (
				& entry_path,
			).map_err (
				|error|

				format! (
					"Unable to create {}: {}",
					& entry_path,
					error.description ())
			)

		);

		try! (

			output.write (
				& stored_data,
			).map_err (
				|error|

				format! (
					"Error writing to {}: {}",
					entry_path,
					error.description ())
			)

		);

		// create and store the filesystem item in the index

		let filesystem_item =
			FilesystemItem {

			storage_manager: self.data.clone (),
			key: key.deref ().to_owned (),
			compressed: compressed,
			uncompressed_size: uncompressed_data.len (),

		};

		self_state.filesystem_items.insert (
			key.deref ().to_owned (),
			filesystem_item);

		Ok (())

	}

	pub fn get (
		& self,
		key: & str,
	) -> Option <BoxFuture <Arc <Vec <u8>>, String>> {

		let mut self_state =
			self.state.lock ().unwrap ();

		// try in uncompressed memory cache

		match (

			self_state.uncompressed_memory_items.get_mut (
				key,
			)

		) {

			Some (item_data) =>
				return Some (
					futures::done (
						Ok (item_data.clone ())
					).boxed (),
				),

			None =>
				(),
		};

		// try in compressed memory cache

		match (

			self_state.compressed_memory_items.get_mut (
				key,
			)

		) {

			Some (
				& mut MemoryCacheItem::Compressed (
					ref compressed_data,
					uncompressed_size)
			) =>
				return Some ({

				futures::done (

					minilzo::decompress (
						& compressed_data,
						uncompressed_size,
					).map (
						|uncompressed_data|

						Arc::new (
							uncompressed_data)

					).map_err (
						|error|

						format! (
							"Decompression failed: {:?}",
							error)

					)

				).boxed ()

			}),

			Some (
				& mut MemoryCacheItem::Uncompressed (
					ref uncompressed_data)
			) =>
				return Some (
					futures::done (
						Ok (uncompressed_data.clone ())
					).boxed (),
				),

			None =>
				(),

		};

		// try in compressed filesystem cache

		Self::get_filesystem (
			self_state.deref_mut (),
			key)

	}

	fn get_filesystem (
		self_state: & mut StorageManagerState,
		key: & str,
	) -> Option <BoxFuture <Arc <Vec <u8>>, String>> {

		match (

			self_state.filesystem_items.get_mut (
				key,
			)

		) {

			Some (filesystem_item) => {

				let uncompressed_data =
					match (

					filesystem_item.get ()

				) {

					Ok (data) =>
						data,

					Err (error) =>
						return Some (
							futures::failed (
								error,
							).boxed ()
						),

				};

				self_state.uncompressed_memory_items.insert (
					key.to_owned (),
					uncompressed_data.clone ());

				Some (futures::done (
					Ok (uncompressed_data)
				).boxed ())

			},

			None =>
				None,

		}

	}

}

impl FilesystemItem {

	fn path (
		& self,
	) -> String {

		format! (
			"{}/{}",
			self.storage_manager.path,
			self.key)

	}

	fn get (
		& self,
	) -> Result <Arc <Vec <u8>>, String> {

		let mut file =
			try! (

			File::open (
				self.path (),
			).map_err (
				|error|

				format! (
					"Error loading storage item {}: {}",
					self.key,
					error.description ())

			)

		);

		let mut stored_data =
			Vec::new ();

		try! (

			file.read_to_end (
				& mut stored_data,
			).map_err (
				|error|

				format! (
					"Error loading storage item {}: {}",
					self.key,
					error.description ())

			)

		);

		if self.compressed {

			let uncompressed_data =
				Arc::new (
					try! (

				minilzo::decompress (
					& stored_data,
					self.uncompressed_size,
				).map_err (
					|error|

					format! (
						"Error decompressing stored data: {:?}",
						error)

				)

			));

			Ok (
				uncompressed_data
			)

		} else {

			Ok (

				Arc::new (
					stored_data)

			)

		}

	}

}

impl Drop for FilesystemItem {

	fn drop (
		& mut self,
	) {

		match (

			fs::remove_file (
				self.path (),
			)

		) {

			Ok (_) => (),

			Err (error) => {

				stderrln! (
					"Error removing storage item {}: {}",
					self.key,
					error.description ());

			}

		}

	}

}

// ex: noet ts=4 filetype=rust
<|endoftext|>