<commit_before>use chan::Sender;
use rustc_serialize::json;
use std::fs::File;
use std::io;
use std::path::PathBuf;

use datatype::{Config, Error, Event, Method, PendingUpdateRequest,
               UpdateRequestId, UpdateReport, UpdateReportWithVin,
               UpdateResultCode, UpdateState, Url};
use http_client::{HttpClient, HttpRequest};

pub struct OTA<'c, 'h> {
    config: &'c Config,
    client: &'h HttpClient,
}

impl<'c, 'h> OTA<'c, 'h> {
    pub fn new(config: &'c Config, client: &'h HttpClient) -> OTA<'c, 'h> {
        OTA { config: config, client: client }
    }

    pub fn update_endpoint(&self, path: &str) -> Url {
        let endpoint = if path.is_empty() {
            format!("/api/v1/vehicle_updates/{}", self.config.auth.vin)
        } else {
            format!("/api/v1/vehicle_updates/{}/{}", self.config.auth.vin, path)
        };
        self.config.ota.server.join(&endpoint).unwrap()
    }

    pub fn get_package_updates(&mut self) -> Result<Vec<PendingUpdateRequest>, Error> {
        debug!("getting package updates");
        let resp_rx = self.client.send_request(HttpRequest {
            method: Method::Get,
            url:    self.update_endpoint(""),
            body:   None,
        });
        let resp = resp_rx.recv().expect("no get_package_updates response received");
        let data = try!(resp);
        let text = try!(String::from_utf8(data));
        Ok(try!(json::decode::<Vec<PendingUpdateRequest>>(&text)))
    }

    pub fn download_package_update(&mut self, id: &UpdateRequestId) -> Result<PathBuf, Error> {
        debug!("downloading package update");
        let resp_rx = self.client.send_request(HttpRequest {
            method: Method::Get,
            url:    self.update_endpoint(&format!("{}/download", id)),
            body:   None,
        });

        let mut path = PathBuf::new();
        path.push(&self.config.ota.packages_dir);
        path.push(id);
        // TODO: Use Content-Disposition filename from request?
        // TODO: Do not invoke package_manager
        path.set_extension(self.config.ota.package_manager.extension());

        let resp     = resp_rx.recv().expect("no download_package_update response received");
        let data     = try!(resp);
        let mut file = try!(File::create(path.as_path()));
        let _        = io::copy(&mut &*data, &mut file);
        Ok(path)
    }

    pub fn install_package_update(&mut self, id: &UpdateRequestId, etx: &Sender<Event>)
                                  -> Result<UpdateReport, Error> {
        debug!("installing package update");
        match self.download_package_update(id) {
            Ok(path) => {
                let err_str  = format!("Path is not valid UTF-8: {:?}", path);
                let pkg_path = try!(path.to_str().ok_or(Error::ParseError(err_str)));
                info!("Downloaded to {:?}. Installing...", pkg_path);

                // TODO: Fire DownloadComplete event, handle async UpdateReport command
                // TODO: Do not invoke package_manager
                let _ = etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installing));
                match self.config.ota.package_manager.install_package(pkg_path) {
                    Ok((code, output)) => {
                        let _ = etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installed));
                        Ok(UpdateReport::new(id.clone(), code, output))
                    }

                    Err((code, output)) => {
                        let err_str = format!("{:?}: {:?}", code, output);
                        let _ = etx.send(Event::UpdateErrored(id.clone(), err_str));
                        Ok(UpdateReport::new(id.clone(), code, output))
                    }
                }
            }

            Err(err) => {
                etx.send(Event::UpdateErrored(id.clone(), format!("{:?}", err)));
                let failed = format!("Download failed: {:?}", err);
                Ok(UpdateReport::new(id.clone(), UpdateResultCode::GENERAL_ERROR, failed))
            }
        }
    }

    pub fn update_installed_packages(&mut self) -> Result<(), Error> {
        debug!("updating installed packages");
        // TODO: Fire GetInstalledSoftware event, handle async InstalledSoftware command
        // TODO: Do not invoke package_manager
        let pkgs = try!(self.config.ota.package_manager.installed_packages());
        let body = try!(json::encode(&pkgs));
        debug!("installed packages: {}", body);
        let _    = self.client.send_request(HttpRequest {
            method: Method::Put,
            url:    self.update_endpoint("installed"),
            body:   Some(body.into_bytes()),
        });
        Ok(())
    }

    pub fn send_install_report(&mut self, report: &UpdateReport) -> Result<(), Error> {
        debug!("sending installation report");
        let vin_report = UpdateReportWithVin::new(&self.config.auth.vin, &report);
        let body       = try!(json::encode(&vin_report));
        let _          = self.client.send_request(HttpRequest {
            method: Method::Post,
            url:    self.update_endpoint(&format!("{}", report.update_id)),
            body:   Some(body.into_bytes()),
        });
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use chan;
    use rustc_serialize::json;

    use super::*;
    use datatype::{Config, Event, Package, PendingUpdateRequest, UpdateResultCode, UpdateState};
    use http_client::TestHttpClient;
    use package_manager::PackageManager;
    use package_manager::tpm::assert_rx;

    #[test]
    fn test_get_package_updates() {
        let pending_update = PendingUpdateRequest {
            requestId: "someid".to_string(),
            installPos: 0,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            createdAt: "2010-01-01".to_string()
        };

        let json    = format!("[{}]", json::encode(&pending_update).unwrap());
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestHttpClient::from(vec![json.to_string()]),
        };

        let updates: Vec<PendingUpdateRequest> = ota.get_package_updates().unwrap();
        let ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();
        assert_eq!(ids, vec!["someid".to_string()])
    }

    #[test]
    fn bad_client_download_package_update() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestHttpClient::new(),
        };
        let expect  = "Http client error: http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download";
        assert_eq!(expect, format!("{}", ota.download_package_update(&"0".to_string()).unwrap_err()));
    }

    #[test]
    fn test_install_package_update_0() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestHttpClient::new(),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update(&"0".to_string(), &tx);
        assert_eq!(report.unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::GENERAL_ERROR);

        let expect = r#"ClientError("http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download")"#;
        assert_rx(rx, &[
            Event::UpdateErrored("0".to_string(), String::from(expect))
        ]);
    }

    #[test]
    fn test_install_package_update_1() {
        let mut config             = Config::default();
        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::new_file(false);

        let mut ota = OTA {
            config: &config,
            client: &mut TestHttpClient::from(vec!["".to_string()]),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update(&"0".to_string(), &tx);
        assert_eq!(report.unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::INSTALL_FAILED);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            // XXX: Not very helpful message?
            Event::UpdateErrored("0".to_string(), r#"INSTALL_FAILED: "failed""#.to_string())
        ]);
    }

    #[test]
    fn test_install_package_update_2() {
        let mut config = Config::default();
        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::new_file(true);

        let replies = vec![
            "[]".to_string(),
            "package data".to_string(),
        ];
        let mut ota = OTA {
            config: &config,
            client: &mut TestHttpClient::from(replies),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update(&"0".to_string(), &tx);
        assert_eq!(report.unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::OK);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installed)
        ]);
    }
}
<commit_msg>Wait for installation report and update installed packages<commit_after>use chan::Sender;
use rustc_serialize::json;
use std::fs::File;
use std::io;
use std::path::PathBuf;

use datatype::{Config, Error, Event, Method, PendingUpdateRequest,
               UpdateRequestId, UpdateReport, UpdateReportWithVin,
               UpdateResultCode, UpdateState, Url};
use http_client::{HttpClient, HttpRequest};

pub struct OTA<'c, 'h> {
    config: &'c Config,
    client: &'h HttpClient,
}

impl<'c, 'h> OTA<'c, 'h> {
    pub fn new(config: &'c Config, client: &'h HttpClient) -> OTA<'c, 'h> {
        OTA { config: config, client: client }
    }

    pub fn update_endpoint(&self, path: &str) -> Url {
        let endpoint = if path.is_empty() {
            format!("/api/v1/vehicle_updates/{}", self.config.auth.vin)
        } else {
            format!("/api/v1/vehicle_updates/{}/{}", self.config.auth.vin, path)
        };
        self.config.ota.server.join(&endpoint).unwrap()
    }

    pub fn get_package_updates(&mut self) -> Result<Vec<PendingUpdateRequest>, Error> {
        debug!("getting package updates");
        let resp_rx = self.client.send_request(HttpRequest {
            method: Method::Get,
            url:    self.update_endpoint(""),
            body:   None,
        });
        let resp = resp_rx.recv().expect("no get_package_updates response received");
        let data = try!(resp);
        let text = try!(String::from_utf8(data));
        Ok(try!(json::decode::<Vec<PendingUpdateRequest>>(&text)))
    }

    pub fn download_package_update(&mut self, id: &UpdateRequestId) -> Result<PathBuf, Error> {
        debug!("downloading package update");
        let resp_rx = self.client.send_request(HttpRequest {
            method: Method::Get,
            url:    self.update_endpoint(&format!("{}/download", id)),
            body:   None,
        });

        let mut path = PathBuf::new();
        path.push(&self.config.ota.packages_dir);
        path.push(id);
        // TODO: Use Content-Disposition filename from request?
        // TODO: Do not invoke package_manager
        path.set_extension(self.config.ota.package_manager.extension());

        let resp     = resp_rx.recv().expect("no download_package_update response received");
        let data     = try!(resp);
        let mut file = try!(File::create(path.as_path()));
        let _        = io::copy(&mut &*data, &mut file);
        Ok(path)
    }

    pub fn install_package_update(&mut self, id: &UpdateRequestId, etx: &Sender<Event>)
                                  -> Result<UpdateReport, Error> {
        debug!("installing package update");
        match self.download_package_update(id) {
            Ok(path) => {
                let err_str  = format!("Path is not valid UTF-8: {:?}", path);
                let pkg_path = try!(path.to_str().ok_or(Error::ParseError(err_str)));
                info!("Downloaded to {:?}. Installing...", pkg_path);

                // TODO: Fire DownloadComplete event, handle async UpdateReport command
                // TODO: Do not invoke package_manager
                let _ = etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installing));
                match self.config.ota.package_manager.install_package(pkg_path) {
                    Ok((code, output)) => {
                        let _ = etx.send(Event::UpdateStateChanged(id.clone(), UpdateState::Installed));
                        Ok(UpdateReport::new(id.clone(), code, output))
                    }

                    Err((code, output)) => {
                        let err_str = format!("{:?}: {:?}", code, output);
                        let _ = etx.send(Event::UpdateErrored(id.clone(), err_str));
                        Ok(UpdateReport::new(id.clone(), code, output))
                    }
                }
            }

            Err(err) => {
                etx.send(Event::UpdateErrored(id.clone(), format!("{:?}", err)));
                let failed = format!("Download failed: {:?}", err);
                Ok(UpdateReport::new(id.clone(), UpdateResultCode::GENERAL_ERROR, failed))
            }
        }
    }

    pub fn update_installed_packages(&mut self) -> Result<(), Error> {
        debug!("updating installed packages");
        // TODO: Fire GetInstalledSoftware event, handle async InstalledSoftware command
        // TODO: Do not invoke package_manager
        let pkgs = try!(self.config.ota.package_manager.installed_packages());
        let body = try!(json::encode(&pkgs));
        debug!("installed packages: {}", body);

        let resp_rx = self.client.send_request(HttpRequest {
            method: Method::Put,
            url:    self.update_endpoint("installed"),
            body:   Some(body.into_bytes()),
        });
        let _ = resp_rx.recv().expect("no update_installed_packages response received")
                       .map_err(|err| error!("update_installed_packages failed: {}", err));
        Ok(())
    }

    pub fn send_install_report(&mut self, report: &UpdateReport) -> Result<(), Error> {
        debug!("sending installation report");
        let vin_report = UpdateReportWithVin::new(&self.config.auth.vin, &report);
        let body       = try!(json::encode(&vin_report));
        let resp_rx    = self.client.send_request(HttpRequest {
            method: Method::Post,
            url:    self.update_endpoint(&format!("{}", report.update_id)),
            body:   Some(body.into_bytes()),
        });
        let resp = resp_rx.recv().expect("no send_install_report response received");
        let _    = try!(resp);
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use chan;
    use rustc_serialize::json;

    use super::*;
    use datatype::{Config, Event, Package, PendingUpdateRequest, UpdateResultCode, UpdateState};
    use http_client::TestHttpClient;
    use package_manager::PackageManager;
    use package_manager::tpm::assert_rx;

    #[test]
    fn test_get_package_updates() {
        let pending_update = PendingUpdateRequest {
            requestId: "someid".to_string(),
            installPos: 0,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            createdAt: "2010-01-01".to_string()
        };

        let json    = format!("[{}]", json::encode(&pending_update).unwrap());
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestHttpClient::from(vec![json.to_string()]),
        };

        let updates: Vec<PendingUpdateRequest> = ota.get_package_updates().unwrap();
        let ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();
        assert_eq!(ids, vec!["someid".to_string()])
    }

    #[test]
    fn bad_client_download_package_update() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestHttpClient::new(),
        };
        let expect  = "Http client error: http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download";
        assert_eq!(expect, format!("{}", ota.download_package_update(&"0".to_string()).unwrap_err()));
    }

    #[test]
    fn test_install_package_update_0() {
        let mut ota = OTA {
            config: &Config::default(),
            client: &mut TestHttpClient::new(),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update(&"0".to_string(), &tx);
        assert_eq!(report.unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::GENERAL_ERROR);

        let expect = r#"ClientError("http://127.0.0.1:8080/api/v1/vehicle_updates/V1234567890123456/0/download")"#;
        assert_rx(rx, &[
            Event::UpdateErrored("0".to_string(), String::from(expect))
        ]);
    }

    #[test]
    fn test_install_package_update_1() {
        let mut config             = Config::default();
        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::new_file(false);

        let mut ota = OTA {
            config: &config,
            client: &mut TestHttpClient::from(vec!["".to_string()]),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update(&"0".to_string(), &tx);
        assert_eq!(report.unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::INSTALL_FAILED);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            // XXX: Not very helpful message?
            Event::UpdateErrored("0".to_string(), r#"INSTALL_FAILED: "failed""#.to_string())
        ]);
    }

    #[test]
    fn test_install_package_update_2() {
        let mut config = Config::default();
        config.ota.packages_dir    = "/tmp/".to_string();
        config.ota.package_manager = PackageManager::new_file(true);

        let replies = vec![
            "[]".to_string(),
            "package data".to_string(),
        ];
        let mut ota = OTA {
            config: &config,
            client: &mut TestHttpClient::from(replies),
        };
        let (tx, rx) = chan::async();
        let report   = ota.install_package_update(&"0".to_string(), &tx);
        assert_eq!(report.unwrap().operation_results.pop().unwrap().result_code,
                   UpdateResultCode::OK);

        assert_rx(rx, &[
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installing),
            Event::UpdateStateChanged("0".to_string(), UpdateState::Installed)
        ]);
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate markovpass;

use markovpass::PassphraseMarkovChain;
use std::io::Write;

fn build_opts() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optopt("n", "", "Number of passphrases to generate (default 1)", "NUM");
    opts.optopt("e", "", "Minimum entropy (default 60)", "MINENTROPY");
    opts.optopt("l", "", "NGram length (default 3)", "LENGTH");
    opts.optopt("w", "", "Minimum word length for corpus (default 5)", "LENGTH");
    opts.optflag("h", "help", "display this help and exit");

    opts
}

fn parse_args(opts: &getopts::Options, args: &Vec<String>)
        -> Result<(String, usize, f64, usize, usize), &'static str> {
    let matches = match opts.parse(&args[1..]) {
        Ok(x) => { x },
        Err(_) => { return Err("Failed to parse arguments."); },
    };

    if matches.opt_present("h") || matches.free.len() > 1 {
        return Err("Failed to parse arguments.");
    };

    macro_rules! get_num_flag {
        ($num_type:ty, $flag:expr, $default:expr) => {
            match matches.opt_str($flag) {
                Some(s) => match s.parse::<$num_type>() {
                    Ok(n) => { n },
                    Err(_) => { return Err("Failed to parse arguments."); }
                },
                None => $default,
            }
        }
    }

    let number = get_num_flag!(usize, "n", 1);
    let min_entropy = get_num_flag!(f64, "e", 60.0);
    let ngram_length = get_num_flag!(usize, "l", 3);
    let min_word_length = get_num_flag!(usize, "w", 5);

    let filename = if matches.free.is_empty() {
        "-".to_string()
    } else {
        matches.free[0].clone()
    };

    Ok((filename, number, min_entropy, ngram_length, min_word_length))
}

fn get_corpus(filename: &str) -> Result<String, std::io::Error> {
    let mut input: Box<std::io::Read> = if filename == "-" {
        Box::new(std::io::stdin())
    } else {
        let file = try!(std::fs::File::open(&filename));
        Box::new(file)
    };
    let mut corpus = String::new();
    try!(input.read_to_string(&mut corpus));

    Ok(corpus)
}

fn clean_word(word: &str, min_length: usize) -> Option<&str> {
    let word = word.trim_matches(|c: char| !c.is_alphabetic());

    if word.chars().all(|c: char| c.is_alphabetic()) && word.len() >= min_length {
        Some(word)
    } else {
        None
    }
}

fn get_ngrams(corpus: &str, ngram_length: usize, min_word_length: usize) -> Vec<String> {
    let words = corpus.split_whitespace()
      .filter_map(|word| clean_word(word, min_word_length));
    let cleaned_corpus = Some("").into_iter().chain(words).collect::<Vec<&str>>().join(" ");
    let char_count = cleaned_corpus.chars().count();
    if char_count < ngram_length { return vec![]; };
    let count = char_count - ngram_length + 1;

    let mut chars = cleaned_corpus.chars();
    let mut ngrams = Vec::with_capacity(count);
    for _ in 0..count {
        let ngram: String = chars.clone().take(ngram_length).collect();
        ngrams.push(ngram.to_lowercase());
        chars.next();
    };

    ngrams
}

fn gen_passphrases(ngrams: &Vec<String>, number: usize, min_entropy: f64)
        -> Result<Vec<(String, f64)>, &'static str> {
    if ngrams.is_empty() { return Err("No NGrams found."); };
    let chain = try!(PassphraseMarkovChain::new(ngrams.iter().cloned()));
    let mut passphrases = Vec::with_capacity(number);
    for _ in 0..number {
        passphrases.push(chain.passphrase(min_entropy));
    };

    Ok(passphrases)
}

fn print_usage(program: &str, opts: &getopts::Options) {
    let brief = format!("Usage: {} [FILE] [options]", program);
    print!("{}", opts.usage(&brief));
}

fn write_error(program: &str, filename: &str, message: &str) {
    writeln!(&mut std::io::stderr(), "{}: {}: {}", &program, &filename, &message)
        .expect("Failed writing to stderr.");
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let program = args[0].clone();
    let opts = build_opts();

    let (filename, number, min_entropy, ngram_length, min_word_length) =
            match parse_args(&opts, &args) {
        Ok(parsed_args) => { parsed_args },
        Err(_) => {
            print_usage(&program, &opts);
            return;
        }
    };
    let corpus = match get_corpus(&filename) {
        Ok(corpus) => { corpus },
        Err(_) => {
            write_error(&program, &filename, "Failed to read input");
            return;
        },
    };
    let ngrams = get_ngrams(&corpus, ngram_length, min_word_length);
    let passphrases = match gen_passphrases(&ngrams, number, min_entropy) {
        Ok(passphrases) => { passphrases },
        Err(e) => {
            write_error(&program, &filename, e);
            return;
        },
    };

    for (passphrase, entropy) in passphrases {
        println!("{} <{}>", passphrase, entropy);
    };
}
<commit_msg>Change gen_passphrases to move instead of borrow<commit_after>extern crate getopts;
extern crate markovpass;

use markovpass::PassphraseMarkovChain;
use std::io::Write;

fn build_opts() -> getopts::Options {
    let mut opts = getopts::Options::new();
    opts.optopt("n", "", "Number of passphrases to generate (default 1)", "NUM");
    opts.optopt("e", "", "Minimum entropy (default 60)", "MINENTROPY");
    opts.optopt("l", "", "NGram length (default 3)", "LENGTH");
    opts.optopt("w", "", "Minimum word length for corpus (default 5)", "LENGTH");
    opts.optflag("h", "help", "display this help and exit");

    opts
}

fn parse_args(opts: &getopts::Options, args: &Vec<String>)
        -> Result<(String, usize, f64, usize, usize), &'static str> {
    let matches = match opts.parse(&args[1..]) {
        Ok(x) => { x },
        Err(_) => { return Err("Failed to parse arguments."); },
    };

    if matches.opt_present("h") || matches.free.len() > 1 {
        return Err("Failed to parse arguments.");
    };

    macro_rules! get_num_flag {
        ($num_type:ty, $flag:expr, $default:expr) => {
            match matches.opt_str($flag) {
                Some(s) => match s.parse::<$num_type>() {
                    Ok(n) => { n },
                    Err(_) => { return Err("Failed to parse arguments."); }
                },
                None => $default,
            }
        }
    }

    let number = get_num_flag!(usize, "n", 1);
    let min_entropy = get_num_flag!(f64, "e", 60.0);
    let ngram_length = get_num_flag!(usize, "l", 3);
    let min_word_length = get_num_flag!(usize, "w", 5);

    let filename = if matches.free.is_empty() {
        "-".to_string()
    } else {
        matches.free[0].clone()
    };

    Ok((filename, number, min_entropy, ngram_length, min_word_length))
}

fn get_corpus(filename: &str) -> Result<String, std::io::Error> {
    let mut input: Box<std::io::Read> = if filename == "-" {
        Box::new(std::io::stdin())
    } else {
        let file = try!(std::fs::File::open(&filename));
        Box::new(file)
    };
    let mut corpus = String::new();
    try!(input.read_to_string(&mut corpus));

    Ok(corpus)
}

fn clean_word(word: &str, min_length: usize) -> Option<&str> {
    let word = word.trim_matches(|c: char| !c.is_alphabetic());

    if word.chars().all(|c: char| c.is_alphabetic()) && word.len() >= min_length {
        Some(word)
    } else {
        None
    }
}

fn get_ngrams(corpus: &str, ngram_length: usize, min_word_length: usize) -> Vec<String> {
    let words = corpus.split_whitespace()
      .filter_map(|word| clean_word(word, min_word_length));
    let cleaned_corpus = Some("").into_iter().chain(words).collect::<Vec<&str>>().join(" ");
    let char_count = cleaned_corpus.chars().count();
    if char_count < ngram_length { return vec![]; };
    let count = char_count - ngram_length + 1;

    let mut chars = cleaned_corpus.chars();
    let mut ngrams = Vec::with_capacity(count);
    for _ in 0..count {
        let ngram: String = chars.clone().take(ngram_length).collect();
        ngrams.push(ngram.to_lowercase());
        chars.next();
    };

    ngrams
}

fn gen_passphrases(ngrams: Vec<String>, number: usize, min_entropy: f64)
        -> Result<Vec<(String, f64)>, &'static str> {
    if ngrams.is_empty() { return Err("No NGrams found."); };
    let chain = try!(PassphraseMarkovChain::new(ngrams.iter().cloned()));
    let mut passphrases = Vec::with_capacity(number);
    for _ in 0..number {
        passphrases.push(chain.passphrase(min_entropy));
    };

    Ok(passphrases)
}

fn print_usage(program: &str, opts: &getopts::Options) {
    let brief = format!("Usage: {} [FILE] [options]", program);
    print!("{}", opts.usage(&brief));
}

fn write_error(program: &str, filename: &str, message: &str) {
    writeln!(&mut std::io::stderr(), "{}: {}: {}", &program, &filename, &message)
        .expect("Failed writing to stderr.");
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let program = args[0].clone();
    let opts = build_opts();

    let (filename, number, min_entropy, ngram_length, min_word_length) =
            match parse_args(&opts, &args) {
        Ok(parsed_args) => { parsed_args },
        Err(_) => {
            print_usage(&program, &opts);
            return;
        }
    };
    let corpus = match get_corpus(&filename) {
        Ok(corpus) => { corpus },
        Err(_) => {
            write_error(&program, &filename, "Failed to read input");
            return;
        },
    };
    let ngrams = get_ngrams(&corpus, ngram_length, min_word_length);
    let passphrases = match gen_passphrases(ngrams, number, min_entropy) {
        Ok(passphrases) => { passphrases },
        Err(e) => {
            write_error(&program, &filename, e);
            return;
        },
    };

    for (passphrase, entropy) in passphrases {
        println!("{} <{}>", passphrase, entropy);
    };
}
<|endoftext|>


<commit_before>#![feature(convert)]
#![feature(buf_stream)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;

use std::net::{TcpListener, TcpStream, Ipv4Addr};
use std::thread;
use std::io::{self,Read,Write,BufStream,BufRead};
use std::str::FromStr;
use std::fmt;
use std::sync::{Arc,Mutex};
use std::collections::HashMap;

use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use yak_client::yak_capnp::*;

type Key = (String, Vec<u8>);
type Val = Vec<u8>;
type Values = Vec<Val>;
#[derive(Debug,Clone)]
struct MemStore (Arc<Mutex<HashMap<Key, Values>>>);

trait Store {
  fn truncate(&self, space: &str);
  fn read(&self, space: &str, key: &[u8]) -> Values;
  fn write(&self, space: &str, key: &[u8], val: &[u8]);
}

impl MemStore {
  fn new() -> MemStore {
    MemStore(Arc::new(Mutex::new(HashMap::new())))
  }
}

impl Store for MemStore {
  fn truncate(&self, space: &str) {
    let mut map = self.0.lock().unwrap();
    let to_rm = map.keys().filter(|k| k.0 == space).map(|k| k.clone()).collect::<Vec<_>>();
    for k in to_rm {
      map.remove(&k);
    }
  }

  fn read(&self, space: &str, key: &[u8]) -> Values {
    let map = self.0.lock().unwrap();
    let k = (space.into(), key.into());
    map.get(&k).map(|x| x.clone()).unwrap_or(vec![])
  }
  fn write(&self, space: &str, key: &[u8], val: &[u8]) {
    let mut map = self.0.lock().unwrap();
    let k = (space.into(), key.into());
    let entry = map.entry(k).or_insert(vec![]);
    entry.push(val.into())
  }
}

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error)
}

pub fn main() {
  env_logger::init().unwrap();

  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next : Option<String> = a.next();

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started on {}, ready to accept", local);
  let mut store = MemStore::new();
  for stream in listener.incoming() {
    let next = next.clone();
    let store = store.clone();
    thread::spawn(move || {
	let mut sock = &stream.unwrap();
	let peer = sock.peer_addr().unwrap();
	info!("Accept stream from {:?}", peer);
        let mut strm = BufStream::new(sock);
        process_requests(peer, strm, store).unwrap()
      });
  }
}

fn process_requests<Id: fmt::Display, S: Read + Write, ST:Store>(id: Id, mut strm: BufStream<S>, store: ST) -> Result<(), ServerError> {
  loop {
    debug!("{}: Waiting for message", id);
    let len = try!(strm.fill_buf()).len();
    if len == 0 {
        debug!("{}: End of client stream", id);
        return Ok(())
    }
    let message_reader = try!(serialize_packed::read_message(&mut strm, ReaderOptions::new()));
    let msg = try!(message_reader.get_root::<client_request::Reader>());
    debug!("{}: Read message", id);

    let mut message = MallocMessageBuilder::new_default();
    {
      let mut response = message.init_root::<client_response::Builder>();
      match try!(msg.which()) {
        client_request::Truncate(v) => truncate(&id, &store, try!(v), response),
          client_request::Read(v) => read(&id, &store, try!(v), response),
          client_request::Write(v) => write(&id, &store, try!(v), response),
      };
    }

    try!(serialize_packed::write_message(&mut strm, &mut message));
    try!(strm.flush())
  }
}

fn truncate<Id: fmt::Display, S: Store>(id: &Id, store: &S, req: truncate_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(req.get_space());
  info!("{}/{:?}: truncate", id, space);
  store.truncate(space);
  response.set_ok(());
  Ok(())
}

fn read<Id: fmt::Display, S: Store>(id: &Id, store: &S, req: read_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(req.get_space());
  let key = try!(req.get_key()).into();
  let val = store.read(space, key);
  info!("{}/{:?}: read:{:?}: -> {:?}", id, space, key, val);

  let mut data = response.init_ok_data(val.len() as u32);
  for i in 0..val.len() {
    let mut datum = data.borrow().get(i as u32);
    datum.set_value(&val[i])
  }
  Ok(())
}

fn write<Id: fmt::Display, S: Store>(id: &Id, store: &S, v: write_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
  let space = try!(v.get_space());
  let key = try!(v.get_key()).into();
  let val = try!(v.get_value()).into();
  info!("{}/{:?}: write:{:?} -> {:?}", id, space, key, val);

  store.write(space, key, val);
  response.set_ok(());
  Ok(())
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}
<commit_msg>Introduce a Session type.<commit_after>#![feature(convert)]
#![feature(buf_stream)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;

use std::net::{TcpListener, TcpStream, Ipv4Addr};
use std::thread;
use std::io::{self,Read,Write,BufStream,BufRead};
use std::str::FromStr;
use std::fmt;
use std::sync::{Arc,Mutex};
use std::collections::HashMap;

use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use yak_client::yak_capnp::*;

type Key = (String, Vec<u8>);
type Val = Vec<u8>;
type Values = Vec<Val>;
#[derive(Debug,Clone)]
struct MemStore (Arc<Mutex<HashMap<Key, Values>>>);

trait Store {
  fn truncate(&self, space: &str);
  fn read(&self, space: &str, key: &[u8]) -> Values;
  fn write(&self, space: &str, key: &[u8], val: &[u8]);
}

impl MemStore {
  fn new() -> MemStore {
    MemStore(Arc::new(Mutex::new(HashMap::new())))
  }
}

impl Store for MemStore {
  fn truncate(&self, space: &str) {
    let mut map = self.0.lock().unwrap();
    let to_rm = map.keys().filter(|k| k.0 == space).map(|k| k.clone()).collect::<Vec<_>>();
    for k in to_rm {
      map.remove(&k);
    }
  }

  fn read(&self, space: &str, key: &[u8]) -> Values {
    let map = self.0.lock().unwrap();
    let k = (space.into(), key.into());
    map.get(&k).map(|x| x.clone()).unwrap_or(vec![])
  }
  fn write(&self, space: &str, key: &[u8], val: &[u8]) {
    let mut map = self.0.lock().unwrap();
    let k = (space.into(), key.into());
    let entry = map.entry(k).or_insert(vec![]);
    entry.push(val.into())
  }
}

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error)
}

pub fn main() {
  env_logger::init().unwrap();

  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next : Option<String> = a.next();

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started on {}, ready to accept", local);
  let mut store = MemStore::new();
  for stream in listener.incoming() {
    let next = next.clone();
    let store = store.clone();
    thread::spawn(move || {
	let mut sock = stream.unwrap();
	let peer = sock.peer_addr().unwrap();
	info!("Accept stream from {:?}", peer);
        Session::new(peer, sock, store).process_requests().unwrap()
      });
  }
}

struct Session<Id, S:Write, ST> {
  id: Id,
  strm: BufStream<S>,
  store: ST
}

impl<Id: fmt::Display, S: Read + Write, ST:Store> Session<Id, S, ST> {
  fn new(id: Id, sock: S, store: ST) -> Session<Id, S, ST> {
    let mut strm = BufStream::new(sock);
    Session { id: id, strm:strm, store: store }
  }
  fn process_requests(&mut self) -> Result<(), ServerError> {
    loop {
      debug!("{}: Waiting for message", self.id);
      let len = try!(self.strm.fill_buf()).len();
      if len == 0 {
          debug!("{}: End of client stream", self.id);
          return Ok(())
      }
      let message_reader = try!(serialize_packed::read_message(&mut self.strm, ReaderOptions::new()));
      let msg = try!(message_reader.get_root::<client_request::Reader>());
      debug!("{}: Read message", self.id);

      let mut message = MallocMessageBuilder::new_default();
      {
        let mut response = message.init_root::<client_response::Builder>();
        match try!(msg.which()) {
          client_request::Truncate(v) => self.truncate(try!(v), response),
          client_request::Read(v) => self.read(try!(v), response),
          client_request::Write(v) => self.write(try!(v), response),
        };
      }

      try!(serialize_packed::write_message(&mut self.strm, &mut message));
      try!(self.strm.flush())
    }
  }

  fn truncate(&self, req: truncate_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
    let space = try!(req.get_space());
    info!("{}/{:?}: truncate", self.id, space);
    self.store.truncate(space);
    response.set_ok(());
    Ok(())
  }

  fn read(&self, req: read_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
    let space = try!(req.get_space());
    let key = try!(req.get_key()).into();
    let val = self.store.read(space, key);
    info!("{}/{:?}: read:{:?}: -> {:?}", self.id, space, key, val);

    let mut data = response.init_ok_data(val.len() as u32);
    for i in 0..val.len() {
      let mut datum = data.borrow().get(i as u32);
      datum.set_value(&val[i])
    }
    Ok(())
  }

  fn write(&self, v: write_request::Reader, mut response: client_response::Builder) -> Result<(), ServerError> {
    let space = try!(v.get_space());
    let key = try!(v.get_key()).into();
    let val = try!(v.get_value()).into();
    info!("{}/{:?}: write:{:?} -> {:?}", self.id, space, key, val);

    self.store.write(space, key, val);
    response.set_ok(());
    Ok(())
  }
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}
<|endoftext|>


<commit_before>#![feature(associated_consts)]

pub extern crate futures;
extern crate c3po;
extern crate mainsail;
extern crate rigging;
extern crate cargonauts_config;
pub extern crate serde;
pub extern crate serde_json as json;
pub extern crate tokio_redis as redis;
extern crate tokio_service;

#[allow(unused_imports)]
#[macro_use] extern crate compass_rose;
#[macro_use] extern crate proc_macro_hack;

#[doc(hidden)]
pub use compass_rose::*;

proc_macro_item_decl! {
    /// The routes DSL
    routes! => routes_impl
}

pub mod config {
    pub use cargonauts_config::CargonautsConfig;
}

#[macro_use]
pub mod resources {
    pub use rigging::Error;
    pub use rigging::environment::Environment;

    pub use rigging::resource::{Resource, Relationship};

    #[macro_export]
    macro_rules! relation {
        ($rel:ident => $resource:ident) => {
            pub struct $rel;

            impl $crate::resources::Relationship for $rel {
                type Related = $resource;
            }
        }
    }
}

pub mod methods {
    pub use rigging::method::Method;
    pub use rigging::routes::{Route, Kind};
    pub use mainsail::methods::*;
}

pub mod formats {

    pub use rigging::format::{Format, BuildFormat, Template, TemplateKey};
    pub use mainsail::formats::Debug;
    pub use mainsail::formats::jsonapi::JsonApi;
    pub use mainsail::formats::handlebars::Handlebars;

    pub mod jsonapi {
        pub use mainsail::formats::jsonapi::{ApiSerialize, ApiDeserialize, Fields, ClientIdPolicy};
    }
}

#[doc(hidden)]
pub mod routing {
    pub use rigging::resource::{ResourceEndpoint, RelationEndpoint, RelationshipLink, RelIds, HasOneEndpoint, HasManyEndpoint};
    pub use rigging::endpoint::{Endpoint, EndpointService};
    pub use rigging::routes::{RoutingTable, RouteBuilder, Handler, path};
    pub use rigging::routes::{AssetHandler, default_asset_handler};
    pub use rigging::environment::EnvBuilder;
    pub use rigging::http::BoxFuture as HttpFuture;
    pub use rigging::format::FormatLender;
}

pub use server::serve;

pub mod server {
    pub use rigging::http::{Request, Response, Error, Service, NewService, serve, Handle, Method};

    pub mod pool {
        pub use rigging::connections::Configure;
        pub use c3po::{Pool, Config};
    }
}

pub mod clients {
    pub use rigging::connections::{Client, ConnectClient, Configure, NewServiceLike};
    pub use c3po::{Config as PoolConfig, Conn};
}

pub mod middleware {
    pub use rigging::endpoint::Request;

    pub mod http {
        pub use rigging::http::{Request, Response, Error, BoxFuture};
    }

    pub use tokio_service::Service;

    pub trait Middleware<S>: Default
    where
        S: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>
    {
        type WrappedService: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>;

        fn wrap(self, service: S) -> Self::WrappedService;
    }
}
<commit_msg>Re-export mock connection.<commit_after>#![feature(associated_consts)]

pub extern crate futures;
extern crate c3po;
extern crate mainsail;
extern crate rigging;
extern crate cargonauts_config;
pub extern crate serde;
pub extern crate serde_json as json;
pub extern crate tokio_redis as redis;
extern crate tokio_service;

#[allow(unused_imports)]
#[macro_use] extern crate compass_rose;
#[macro_use] extern crate proc_macro_hack;

#[doc(hidden)]
pub use compass_rose::*;

proc_macro_item_decl! {
    /// The routes DSL
    routes! => routes_impl
}

pub mod config {
    pub use cargonauts_config::CargonautsConfig;
}

#[macro_use]
pub mod resources {
    pub use rigging::Error;
    pub use rigging::environment::Environment;

    pub use rigging::resource::{Resource, Relationship};

    #[macro_export]
    macro_rules! relation {
        ($rel:ident => $resource:ident) => {
            pub struct $rel;

            impl $crate::resources::Relationship for $rel {
                type Related = $resource;
            }
        }
    }
}

pub mod methods {
    pub use rigging::method::Method;
    pub use rigging::routes::{Route, Kind};
    pub use mainsail::methods::*;
}

pub mod formats {

    pub use rigging::format::{Format, BuildFormat, Template, TemplateKey};
    pub use mainsail::formats::Debug;
    pub use mainsail::formats::jsonapi::JsonApi;
    pub use mainsail::formats::handlebars::Handlebars;

    pub mod jsonapi {
        pub use mainsail::formats::jsonapi::{ApiSerialize, ApiDeserialize, Fields, ClientIdPolicy};
    }
}

#[doc(hidden)]
pub mod routing {
    pub use rigging::resource::{ResourceEndpoint, RelationEndpoint, RelationshipLink, RelIds, HasOneEndpoint, HasManyEndpoint};
    pub use rigging::endpoint::{Endpoint, EndpointService};
    pub use rigging::routes::{RoutingTable, RouteBuilder, Handler, path};
    pub use rigging::routes::{AssetHandler, default_asset_handler};
    pub use rigging::environment::EnvBuilder;
    pub use rigging::http::BoxFuture as HttpFuture;
    pub use rigging::format::FormatLender;
}

pub use server::serve;

pub mod server {
    pub use rigging::http::{Request, Response, Error, Service, NewService, serve, Handle, Method};

    pub mod pool {
        pub use rigging::connections::Configure;
        pub use c3po::{Pool, Config};
    }
}

pub mod clients {
    pub use rigging::connections::{Client, ConnectClient, Configure, NewServiceLike};
    pub use c3po::{Config as PoolConfig, Conn};

    pub mod mock {
        pub use rigging::connections::mock::MockConnection;
    }
}

pub mod middleware {
    pub use rigging::endpoint::Request;

    pub mod http {
        pub use rigging::http::{Request, Response, Error, BoxFuture};
    }

    pub use tokio_service::Service;

    pub trait Middleware<S>: Default
    where
        S: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>
    {
        type WrappedService: Service<Request = Request, Response = http::Response, Error = http::Error, Future = http::BoxFuture>;

        fn wrap(self, service: S) -> Self::WrappedService;
    }
}
<|endoftext|>


<commit_before>use chattium_oxide_lib::json::{FromJsonnable, ToJsonnable};
use chattium_oxide_lib::ChatMessage;
use hyper::server::{Handler, Request, Response};
use hyper::header::{ContentLength, ContentType};
use hyper::status::StatusCode;
use hyper::method::Method;
use time::{strftime, Tm};
use std::sync::RwLock;
use std::io::{Read, Write, stderr};

pub struct ClientHandler {
	messages: RwLock<Vec<ChatMessage>>,
}

impl ClientHandler {
	pub fn new() -> ClientHandler {
		ClientHandler{
			messages: RwLock::new(Vec::new()),
		}
	}
}

impl Handler for ClientHandler {
	fn handle(&self, req: Request, mut res: Response) {
		let mut req = req;
		let mut body = "".to_string();

		let mut reqbody = String::new();
		*res.status_mut() = match req.read_to_string(&mut reqbody) {
			Ok(_) =>
				match req.method {
					Method::Post =>
						match ChatMessage::from_json_string(&reqbody) {
							Ok(mut message) => {
								message.sender.fill_ip(req.remote_addr);
								println!("{}: {} @ {}", message.sender.name, message.value, strftime("%T", &message.time_posted).unwrap());
								self.messages.write().unwrap().push(message);
								StatusCode::Ok
							},
							Err(error) => {
								let _ = stderr().write_fmt(format_args!("Couldn't process POSTed message from {}: {}\n", req.remote_addr, error));
								StatusCode::UnprocessableEntity
							},
						},
					Method::Get => {  // Web browser
						body = format!("{}, use chattium-oxide-client to connect to chat",
						               req.remote_addr);
						res.headers_mut().set(ContentType::html());
						StatusCode::Ok
					},
					Method::Trace => {
						match Tm::from_json_string(&reqbody) {
							Ok(ts) => {
								let messages = self.messages.read().unwrap();
								let msgs: Vec<ChatMessage> = messages.iter().rev().take_while(|&m| m.time_posted >= ts).collect::<Vec<&_>>()
								                                     .iter().rev().map(|&m| m.clone()).collect();
								match msgs.to_json_string() {
									Ok(msgs) => {
										body = msgs;
										StatusCode::Ok
									},
									Err(error) => {
										let _ = stderr().write_fmt(format_args!("Couldn't create a JSON response for {}: {}\n", req.remote_addr, error));
										body = "[]".to_string();  // Empty array
										StatusCode::Accepted
									},
								}
							},
							Err(error) => {
								let _ = stderr().write_fmt(format_args!("Couldn't process a TRACE timestamp ({:?}) {}: {}\n", reqbody, req.remote_addr, error));
								StatusCode::UnprocessableEntity
							},
						}
					},
				  _ => StatusCode::ImATeapot,
				},
			Err(error) => {
				let _ = stderr().write_fmt(format_args!("Failed reading request from {}: {}\n", req.remote_addr, error));
				StatusCode::UnsupportedMediaType  // non-UTF-8
			},
		};

		res.headers_mut().set(ContentLength(body.len() as u64));
		if let Err(error) = res.start().unwrap().write_all(body.as_bytes()) {
			let _ = stderr().write_fmt(format_args!("Failed to respond to {}: {}", req.remote_addr, error));
		}
	}
}
<commit_msg>Fill in id for incoming messages<commit_after>use chattium_oxide_lib::json::{FromJsonnable, ToJsonnable};
use chattium_oxide_lib::ChatMessage;
use hyper::server::{Handler, Request, Response};
use hyper::header::{ContentLength, ContentType};
use hyper::status::StatusCode;
use hyper::method::Method;
use time::{strftime, Tm};
use std::sync::RwLock;
use std::io::{Read, Write, stderr};

pub struct ClientHandler {
	messages: RwLock<Vec<ChatMessage>>,
	message_id: RwLock<u64>,
}

impl ClientHandler {
	pub fn new() -> ClientHandler {
		ClientHandler{
			messages: RwLock::new(Vec::new()),
			message_id: RwLock::new(1),
		}
	}
}

impl Handler for ClientHandler {
	fn handle(&self, req: Request, mut res: Response) {
		let mut req = req;
		let mut body = "".to_string();

		let mut reqbody = String::new();
		*res.status_mut() = match req.read_to_string(&mut reqbody) {
			Ok(_) =>
				match req.method {
					Method::Post =>
						match ChatMessage::from_json_string(&reqbody) {
							Ok(mut message) => {
								message.sender.fill_ip(req.remote_addr);
								message.fill_id(self.message_id.write().unwrap());
								println!("{}: {} @ {}", message.sender.name, message.value, strftime("%T", &message.time_posted).unwrap());
								self.messages.write().unwrap().push(message);
								StatusCode::Ok
							},
							Err(error) => {
								let _ = stderr().write_fmt(format_args!("Couldn't process POSTed message from {}: {}\n", req.remote_addr, error));
								StatusCode::UnprocessableEntity
							},
						},
					Method::Get => {  // Web browser
						body = format!("{}, use chattium-oxide-client to connect to chat",
						               req.remote_addr);
						res.headers_mut().set(ContentType::html());
						StatusCode::Ok
					},
					Method::Trace => {
						match Tm::from_json_string(&reqbody) {
							Ok(ts) => {
								let messages = self.messages.read().unwrap();
								let msgs = messages.iter().rev().take_while(|&m| m.time_posted >= ts).collect::<Vec<&_>>()
								                   .iter().rev().map(|&m| m.clone()).collect::<Vec<_>>();
								match msgs.to_json_string() {
									Ok(msgs) => {
										body = msgs;
										StatusCode::Ok
									},
									Err(error) => {
										let _ = stderr().write_fmt(format_args!("Couldn't create a JSON response for {}: {}\n", req.remote_addr, error));
										body = "[]".to_string();  // Empty array
										StatusCode::Accepted
									},
								}
							},
							Err(error) => {
								let _ = stderr().write_fmt(format_args!("Couldn't process a TRACE timestamp ({:?}) {}: {}\n", reqbody, req.remote_addr, error));
								StatusCode::UnprocessableEntity
							},
						}
					},
				  _ => StatusCode::ImATeapot,
				},
			Err(error) => {
				let _ = stderr().write_fmt(format_args!("Failed reading request from {}: {}\n", req.remote_addr, error));
				StatusCode::UnsupportedMediaType  // non-UTF-8
			},
		};

		res.headers_mut().set(ContentLength(body.len() as u64));
		if let Err(error) = res.start().unwrap().write_all(body.as_bytes()) {
			let _ = stderr().write_fmt(format_args!("Failed to respond to {}: {}", req.remote_addr, error));
		}
	}
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route_recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + 'static + Share>>>
}

macro_rules! method_map(
    ($method:ident => $variant:ty) => (
        pub fn $method<'a, H: 'static + Handler>(&'a mut self, pattern: &str, handler: H)
                                                -> &'a mut RouteBuilder
        {
            self.map(conduit::$variant, pattern, handler)
        }
    )
)

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + 'static + Share>>, String>
    {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: 'static + Handler + Share>(&'a mut self,
                                                 method: Method,
                                                 pattern: &str,
                                                 handler: H)
                                                 -> &'a mut RouteBuilder
    {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + 'static + Share>);
        }
        self
    }

    pub fn get<'a, H: 'static + Handler + Share>(&'a mut self, pattern: &str,
                                                 handler: H)
                                                 -> &'a mut RouteBuilder
    {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: 'static + Handler + Share>(&'a mut self, pattern: &str,
                                                  handler: H)
                                                  -> &'a mut RouteBuilder
    {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: 'static + Handler + Share>(&'a mut self, pattern: &str,
                                                 handler: H)
                                                 -> &'a mut RouteBuilder
    {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: 'static + Handler + Share>(&'a mut self, pattern: &str,
                                                    handler: H)
                                                    -> &'a mut RouteBuilder
    {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: 'static + Handler + Share>(&'a mut self, pattern: &str,
                                                  handler: H)
                                                  -> &'a mut RouteBuilder
    {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a mut Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.as_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a mut Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

//impl<T: Request> RequestParams for T {}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn as_conduit_handler() {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", handler1);
        router.get("/posts/:id", handler1);

        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "1, Get".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "10, Post".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn handler1(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<commit_msg>Update with master conduit<commit_after>#![feature(macro_rules)]
#![feature(globs)]

extern crate router = "route_recognizer";
extern crate conduit;

use std::collections::HashMap;
use std::any::{Any, AnyRefExt};
use std::fmt::Show;

use router::{Router, Match};
use conduit::{Method, Handler, Request, Response};

pub struct RouteBuilder {
    routers: HashMap<Method, Router<Box<Handler + Send + Share>>>
}

macro_rules! method_map(
    ($method:ident => $variant:ty) => (
        pub fn $method<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                                -> &'a mut RouteBuilder
        {
            self.map(conduit::$variant, pattern, handler)
        }
    )
)

impl RouteBuilder {
    pub fn new() -> RouteBuilder {
        RouteBuilder { routers: HashMap::new() }
    }

    pub fn recognize<'a>(&'a self, method: &Method, path: &str)
                         -> Result<Match<&'a Box<Handler + Send + Share>>, String>
    {
        match self.routers.find(method) {
            None => Err(format!("No router found for {}", method)),
            Some(router) => router.recognize(path)
        }
    }

    pub fn map<'a, H: Handler>(&'a mut self, method: Method, pattern: &str,
                               handler: H) -> &'a mut RouteBuilder {
        {
            let router = self.routers.find_or_insert_with(method, |_| Router::new());
            router.add(pattern, box handler as Box<Handler + Send + Share>);
        }
        self
    }

    pub fn get<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder {
        self.map(conduit::Get, pattern, handler)
    }

    pub fn post<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder
    {
        self.map(conduit::Post, pattern, handler)
    }

    pub fn put<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                               -> &'a mut RouteBuilder
    {
        self.map(conduit::Put, pattern, handler)
    }

    pub fn delete<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                  -> &'a mut RouteBuilder
    {
        self.map(conduit::Delete, pattern, handler)
    }

    pub fn head<'a, H: Handler>(&'a mut self, pattern: &str, handler: H)
                                -> &'a mut RouteBuilder
    {
        self.map(conduit::Head, pattern, handler)
    }
}

impl conduit::Handler for RouteBuilder {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let m = {
            let method = request.method();
            let path = request.path();

            match self.recognize(&method, path) {
                Ok(m) => m,
                Err(e) => return Err(box e as Box<Show>)
            }
        };

        {
            let extensions = request.mut_extensions();
            extensions.insert("router.params", box m.params.clone() as Box<Any>);
        }

        (*m.handler).call(request)
    }
}

pub trait RequestParams<'a> {
    fn params(self) -> &'a router::Params;
}

pub fn params<'a>(req: &'a mut Request) -> &'a router::Params {
    req.extensions().find(&"router.params")
        .and_then(|a| a.as_ref::<router::Params>())
        .expect("Missing params")
}

impl<'a> RequestParams<'a> for &'a mut Request {
    fn params(self) -> &'a router::Params {
        params(self)
    }
}

//impl<T: Request> RequestParams for T {}

#[cfg(test)]
mod tests {
    extern crate semver;
    use std::io::net::ip::IpAddr;
    use std::collections::HashMap;
    use std::io::MemReader;
    use super::*;

    use conduit;
    use conduit::{Handler, Method, Scheme, Host, Headers, Extensions};

    struct RequestSentinel {
        method: Method,
        path: String,
        extensions: conduit::Extensions
    }

    impl RequestSentinel {
        fn new(method: Method, path: &'static str) -> RequestSentinel {
            RequestSentinel {
                path: path.to_str(),
                extensions: HashMap::new(),
                method: method
            }
        }
    }

    impl conduit::Request for RequestSentinel {
        fn http_version(&self) -> semver::Version { unimplemented!() }
        fn conduit_version(&self) -> semver::Version { unimplemented!() }
        fn method(&self) -> Method { self.method }
        fn scheme(&self) -> Scheme { unimplemented!() }
        fn host<'a>(&'a self) -> Host<'a> { unimplemented!() }
        fn virtual_root<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn path<'a>(&'a self) -> &'a str {
            self.path.as_slice()
        }
        fn query_string<'a>(&'a self) -> Option<&'a str> { unimplemented!() }
        fn remote_ip(&self) -> IpAddr { unimplemented!() }
        fn content_length(&self) -> Option<uint> { unimplemented!() }
        fn headers<'a>(&'a self) -> &'a Headers { unimplemented!() }
        fn body<'a>(&'a mut self) -> &'a mut Reader { unimplemented!() }
        fn extensions<'a>(&'a self) -> &'a Extensions {
            &self.extensions
        }
        fn mut_extensions<'a>(&'a mut self) -> &'a mut Extensions {
            &mut self.extensions
        }
    }

    #[test]
    fn as_conduit_handler() {
        let mut router = RouteBuilder::new();
        router.post("/posts/:id", handler1);
        router.get("/posts/:id", handler1);

        let mut req = RequestSentinel::new(conduit::Get, "/posts/1");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "1, Get".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/posts/10");
        let mut res = router.call(&mut req).ok().expect("No response");

        assert_eq!(res.status, (200, "OK"));
        assert_eq!(res.body.read_to_str().unwrap(), "10, Post".to_str());

        let mut req = RequestSentinel::new(conduit::Post, "/nonexistent");
        router.call(&mut req).err().expect("No response");
    }

    fn handler1(req: &mut conduit::Request) -> Result<conduit::Response, ()> {
        let mut res = vec!();
        res.push(req.params()["id"]);
        res.push(format!("{}", req.method()));

        Ok(conduit::Response {
            status: (200, "OK"),
            headers: HashMap::new(),
            body: box MemReader::new(res.connect(", ").into_bytes())
        })
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use mpv::*;
use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use std::env;
use std::panic::AssertUnwindSafe;
use std::rc::Rc;
use std::time::Duration;

struct Draw {}

pub fn exec() {
    let path = env::args().nth(1).expect("Expected path to media as argument, found nil.");

    // Check for driver availability
    let driver_index = if let Some(i) = sdl2::render::drivers().position(|e| e.name == "opengl") {
        i
    } else {
        panic!("OpenGl driver not found!")
    };

    // Create SDL state
    let sdl = sdl2::init().unwrap();
    let video_subsystem = Rc::new(sdl.video().unwrap());
    let vs = video_subsystem.clone();
    let window = vs.window("mpv-rs sdl2 example", 1280, 720)
        .resizable()
        .position_centered()
        .opengl()
        .build()
        .unwrap();
    let renderer = window.renderer()
        .index(driver_index as _)
        .build()
        .expect("Failed to create renderer with given parameters");
    let wref = renderer.window().unwrap();
    let mut event_pump = sdl.event_pump().unwrap();
    let events = sdl.event().unwrap();
    events.register_custom_event::<Draw>().unwrap();

    // Create mpv state
    let mpv = Parent::with_options(false,
                                   &[("vo", "opengl-cb".into()),
                                     ("cache-initial", 1.into()),
                                     ("volume", 30.into()),
                                     ("ytdl", true.into())])
            .unwrap();
    let vs = video_subsystem.clone();
    let mut mpv_ogl = mpv.create_opengl_context(move |name| vs.gl_get_proc_address(name)).unwrap();
    unsafe { mpv_ogl.set_update_callback(AssertUnwindSafe(events), gl_update_callback) };

    // Load specified file
    mpv.playlist_load_files(&[(&path, FileState::AppendPlay, None)]).unwrap();

    // Setup event handling
    'main: loop {
        for event in event_pump.wait_iter() {
            if event.is_user_event() {
                // The only user event is `Draw`, we don't have to check.
                let (width, height) = wref.size();
                unsafe {
                    mpv_ogl.draw(0, width as _, -(height as isize)).unwrap();
                }
                wref.gl_swap_window();
                continue;
            }

            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } |
                Event::KeyDown { keycode: Some(Keycode::Q), .. } => {
                    break 'main;
                }
                Event::KeyDown { keycode: Some(Keycode::Space), repeat: false, .. } => {
                    if let Data::Flag(true) = mpv.get_property("pause", Format::Flag).unwrap() {
                        mpv.unpause().unwrap();
                    } else {
                        mpv.pause().unwrap();
                    }
                }
                Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
                    mpv.seek_forward(&Duration::from_secs(10)).unwrap();
                }
                _ => {}
            }
        }
    }
}

fn gl_update_callback(events: &AssertUnwindSafe<sdl2::EventSubsystem>) {
    events.push_custom_event(Draw {}).unwrap()
}
<commit_msg>[examples] move callback function into closure<commit_after>// Copyright (C) 2016  ParadoxSpiral
//
// This file is part of mpv-rs.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use mpv::*;
use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

use std::env;
use std::panic::AssertUnwindSafe;
use std::rc::Rc;
use std::time::Duration;

struct Draw {}

pub fn exec() {
    let path = env::args().nth(1).expect("Expected path to media as argument, found nil.");

    // Check for driver availability
    let driver_index = if let Some(i) = sdl2::render::drivers().position(|e| e.name == "opengl") {
        i
    } else {
        panic!("OpenGl driver not found!")
    };

    // Create SDL state
    let sdl = sdl2::init().unwrap();
    let video_subsystem = Rc::new(sdl.video().unwrap());
    let vs = video_subsystem.clone();
    let window = vs.window("mpv-rs sdl2 example", 1280, 720)
        .resizable()
        .position_centered()
        .opengl()
        .build()
        .unwrap();
    let renderer = window.renderer()
        .index(driver_index as _)
        .build()
        .expect("Failed to create renderer with given parameters");
    let wref = renderer.window().unwrap();
    let mut event_pump = sdl.event_pump().unwrap();
    let events = sdl.event().unwrap();
    events.register_custom_event::<Draw>().unwrap();

    // Create mpv state
    let mpv = Parent::with_options(false,
                                   &[("vo", "opengl-cb".into()),
                                     ("cache-initial", 1.into()),
                                     ("volume", 30.into()),
                                     ("ytdl", true.into())])
            .unwrap();
    let vs = video_subsystem.clone();
    let mut mpv_ogl = mpv.create_opengl_context(move |name| vs.gl_get_proc_address(name)).unwrap();
    unsafe { mpv_ogl.set_update_callback(AssertUnwindSafe(events),
                                         |events| events.push_custom_event(Draw {}).unwrap()) };

    // Load specified file
    mpv.playlist_load_files(&[(&path, FileState::AppendPlay, None)]).unwrap();

    // Setup event handling
    'main: loop {
        for event in event_pump.wait_iter() {
            if event.is_user_event() {
                // The only user event is `Draw`, we don't have to check.
                let (width, height) = wref.size();
                unsafe {
                    mpv_ogl.draw(0, width as _, -(height as isize)).unwrap();
                }
                wref.gl_swap_window();
                continue;
            }

            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } |
                Event::KeyDown { keycode: Some(Keycode::Q), .. } => {
                    break 'main;
                }
                Event::KeyDown { keycode: Some(Keycode::Space), repeat: false, .. } => {
                    if let Data::Flag(true) = mpv.get_property("pause", Format::Flag).unwrap() {
                        mpv.unpause().unwrap();
                    } else {
                        mpv.pause().unwrap();
                    }
                }
                Event::KeyDown { keycode: Some(Keycode::Right), repeat: false, .. } => {
                    mpv.seek_forward(&Duration::from_secs(10)).unwrap();
                }
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io::{Seek, Write};
use std::iter::Iterator;
use zip::result::ZipError;
use zip::write::FileOptions;

use std::fs::File;
use std::path::Path;
use walkdir::{DirEntry, WalkDir};

fn main() {
    std::process::exit(real_main());
}

const METHOD_STORED: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Stored);

#[cfg(any(
    feature = "deflate",
    feature = "deflate-miniz",
    feature = "deflate-zlib"
))]
const METHOD_DEFLATED: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Deflated);
#[cfg(not(any(
    feature = "deflate",
    feature = "deflate-miniz",
    feature = "deflate-zlib"
)))]
const METHOD_DEFLATED: Option<zip::CompressionMethod> = None;

#[cfg(feature = "bzip2")]
const METHOD_BZIP2: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Bzip2);
#[cfg(not(feature = "bzip2"))]
const METHOD_BZIP2: Option<zip::CompressionMethod> = None;

fn real_main() -> i32 {
    let args: Vec<_> = std::env::args().collect();
    if args.len() < 3 {
        println!(
            "Usage: {} <source_directory> <destination_zipfile>",
            args[0]
        );
        return 1;
    }

    let src_dir = &*args[1];
    let dst_file = &*args[2];
    for &method in [METHOD_STORED, METHOD_DEFLATED, METHOD_BZIP2].iter() {
        if method.is_none() {
            continue;
        }
        match doit(src_dir, dst_file, method.unwrap()) {
            Ok(_) => println!("done: {} written to {}", src_dir, dst_file),
            Err(e) => println!("Error: {:?}", e),
        }
    }

    0
}

fn zip_dir<T>(
    it: &mut dyn Iterator<Item = DirEntry>,
    prefix: &str,
    writer: T,
    method: zip::CompressionMethod,
) -> zip::result::ZipResult<()>
where
    T: Write + Seek,
{
    let mut zip = zip::ZipWriter::new(writer);
    let options = FileOptions::default()
        .compression_method(method)
        .unix_permissions(0o755);

    let mut buffer = Vec::new();
    for entry in it {
        let path = entry.path();
        let name = path.strip_prefix(Path::new(prefix)).unwrap();

        // Write file or directory explicitly
        // Some unzip tools unzip files with directory paths correctly, some do not!
        if path.is_file() {
            println!("adding file {:?} as {:?} ...", path, name);
            #[allow(deprecated)]
            zip.start_file_from_path(name, options)?;
            let mut f = File::open(path)?;

            f.read_to_end(&mut buffer)?;
            zip.write_all(&*buffer)?;
            buffer.clear();
        } else if !name.as_os_str().is_empty() {
            // Only if not root! Avoids path spec / warning
            // and mapname conversion failed error on unzip
            println!("adding dir {:?} as {:?} ...", path, name);
            #[allow(deprecated)]
            zip.add_directory_from_path(name, options)?;
        }
    }
    zip.finish()?;
    Result::Ok(())
}

fn doit(
    src_dir: &str,
    dst_file: &str,
    method: zip::CompressionMethod,
) -> zip::result::ZipResult<()> {
    if !Path::new(src_dir).is_dir() {
        return Err(ZipError::FileNotFound);
    }

    let path = Path::new(dst_file);
    let file = File::create(&path).unwrap();

    let walkdir = WalkDir::new(src_dir.to_string());
    let it = walkdir.into_iter();

    zip_dir(&mut it.filter_map(|e| e.ok()), src_dir, file, method)?;

    Ok(())
}
<commit_msg>fix: Clippy fix<commit_after>use std::io::prelude::*;
use std::io::{Seek, Write};
use std::iter::Iterator;
use zip::result::ZipError;
use zip::write::FileOptions;

use std::fs::File;
use std::path::Path;
use walkdir::{DirEntry, WalkDir};

fn main() {
    std::process::exit(real_main());
}

const METHOD_STORED: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Stored);

#[cfg(any(
    feature = "deflate",
    feature = "deflate-miniz",
    feature = "deflate-zlib"
))]
const METHOD_DEFLATED: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Deflated);
#[cfg(not(any(
    feature = "deflate",
    feature = "deflate-miniz",
    feature = "deflate-zlib"
)))]
const METHOD_DEFLATED: Option<zip::CompressionMethod> = None;

#[cfg(feature = "bzip2")]
const METHOD_BZIP2: Option<zip::CompressionMethod> = Some(zip::CompressionMethod::Bzip2);
#[cfg(not(feature = "bzip2"))]
const METHOD_BZIP2: Option<zip::CompressionMethod> = None;

fn real_main() -> i32 {
    let args: Vec<_> = std::env::args().collect();
    if args.len() < 3 {
        println!(
            "Usage: {} <source_directory> <destination_zipfile>",
            args[0]
        );
        return 1;
    }

    let src_dir = &*args[1];
    let dst_file = &*args[2];
    for &method in [METHOD_STORED, METHOD_DEFLATED, METHOD_BZIP2].iter() {
        if method.is_none() {
            continue;
        }
        match doit(src_dir, dst_file, method.unwrap()) {
            Ok(_) => println!("done: {} written to {}", src_dir, dst_file),
            Err(e) => println!("Error: {:?}", e),
        }
    }

    0
}

fn zip_dir<T>(
    it: &mut dyn Iterator<Item = DirEntry>,
    prefix: &str,
    writer: T,
    method: zip::CompressionMethod,
) -> zip::result::ZipResult<()>
where
    T: Write + Seek,
{
    let mut zip = zip::ZipWriter::new(writer);
    let options = FileOptions::default()
        .compression_method(method)
        .unix_permissions(0o755);

    let mut buffer = Vec::new();
    for entry in it {
        let path = entry.path();
        let name = path.strip_prefix(Path::new(prefix)).unwrap();

        // Write file or directory explicitly
        // Some unzip tools unzip files with directory paths correctly, some do not!
        if path.is_file() {
            println!("adding file {:?} as {:?} ...", path, name);
            #[allow(deprecated)]
            zip.start_file_from_path(name, options)?;
            let mut f = File::open(path)?;

            f.read_to_end(&mut buffer)?;
            zip.write_all(&*buffer)?;
            buffer.clear();
        } else if !name.as_os_str().is_empty() {
            // Only if not root! Avoids path spec / warning
            // and mapname conversion failed error on unzip
            println!("adding dir {:?} as {:?} ...", path, name);
            #[allow(deprecated)]
            zip.add_directory_from_path(name, options)?;
        }
    }
    zip.finish()?;
    Result::Ok(())
}

fn doit(
    src_dir: &str,
    dst_file: &str,
    method: zip::CompressionMethod,
) -> zip::result::ZipResult<()> {
    if !Path::new(src_dir).is_dir() {
        return Err(ZipError::FileNotFound);
    }

    let path = Path::new(dst_file);
    let file = File::create(&path).unwrap();

    let walkdir = WalkDir::new(src_dir);
    let it = walkdir.into_iter();

    zip_dir(&mut it.filter_map(|e| e.ok()), src_dir, file, method)?;

    Ok(())
}
<|endoftext|>


<commit_before>
pub mod options;
pub mod metadata;
mod limits;
mod rustwide_builder;
mod crates;
mod queue;

pub use self::rustwide_builder::RustwideBuilder;
pub(crate) use self::rustwide_builder::BuildResult;
pub(crate) use self::limits::Limits;

use std::fs;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;
use std::collections::BTreeSet;
use DocBuilderOptions;
use error::Result;

/// chroot based documentation builder
pub struct DocBuilder {
    options: DocBuilderOptions,
    cache: BTreeSet<String>,
    db_cache: BTreeSet<String>,
}

impl DocBuilder {
    pub fn new(options: DocBuilderOptions) -> DocBuilder {
        DocBuilder {
            options: options,
            cache: BTreeSet::new(),
            db_cache: BTreeSet::new(),
        }
    }

    /// Loads build cache
    pub fn load_cache(&mut self) -> Result<()> {
        debug!("Loading cache");
        let path = PathBuf::from(&self.options.prefix).join("cache");
        let reader = fs::File::open(path).map(|f| BufReader::new(f));

        if reader.is_err() {
            return Ok(());
        }

        for line in reader.unwrap().lines() {
            self.cache.insert(line?);
        }

        self.load_database_cache()?;

        Ok(())
    }

    fn load_database_cache(&mut self) -> Result<()> {
        debug!("Loading database cache");
        use db::connect_db;
        let conn = connect_db()?;

        for row in &conn.query("SELECT name, version FROM crates, releases \
                               WHERE crates.id = releases.crate_id",
                   &[])
            .unwrap() {
            let name: String = row.get(0);
            let version: String = row.get(1);
            self.db_cache.insert(format!("{}-{}", name, version));
        }

        Ok(())
    }

    /// Saves build cache
    pub fn save_cache(&self) -> Result<()> {
        debug!("Saving cache");
        let path = PathBuf::from(&self.options.prefix).join("cache");
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(path)?;
        for krate in &self.cache {
            writeln!(file, "{}", krate)?;
        }
        Ok(())
    }

    fn lock_path(&self) -> PathBuf {
        self.options.prefix.join("cratesfyi.lock")
    }

    /// Creates a lock file. Daemon will check this lock file and stop operating if its exists.
    pub fn lock(&self) -> Result<()> {
        let path = self.lock_path();
        if !path.exists() {
            fs::OpenOptions::new().write(true).create(true).open(path)?;
        }
        Ok(())
    }

    /// Removes lock file.
    pub fn unlock(&self) -> Result<()> {
        let path = self.lock_path();
        if path.exists() {
            fs::remove_file(path)?;
        }
        Ok(())
    }

    /// Checks for the lock file and returns whether it currently exists.
    pub fn is_locked(&self) -> bool {
        self.lock_path().exists()
    }

    /// Returns a reference of options
    pub fn options(&self) -> &DocBuilderOptions {
        &self.options
    }

    fn add_to_cache(&mut self, name: &str, version: &str) {
        self.cache.insert(format!("{}-{}", name, version));
    }

    fn should_build(&self, name: &str, version: &str) -> bool {
        let name = format!("{}-{}", name, version);
        let local = self.options.skip_if_log_exists && self.cache.contains(&name);
        let db = self.options.skip_if_exists && self.db_cache.contains(&name);
        !(local || db)
    }
}
<commit_msg>don't ignore DB cache if local cache is empty<commit_after>
pub mod options;
pub mod metadata;
mod limits;
mod rustwide_builder;
mod crates;
mod queue;

pub use self::rustwide_builder::RustwideBuilder;
pub(crate) use self::rustwide_builder::BuildResult;
pub(crate) use self::limits::Limits;

use std::fs;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::PathBuf;
use std::collections::BTreeSet;
use DocBuilderOptions;
use error::Result;

/// chroot based documentation builder
pub struct DocBuilder {
    options: DocBuilderOptions,
    cache: BTreeSet<String>,
    db_cache: BTreeSet<String>,
}

impl DocBuilder {
    pub fn new(options: DocBuilderOptions) -> DocBuilder {
        DocBuilder {
            options: options,
            cache: BTreeSet::new(),
            db_cache: BTreeSet::new(),
        }
    }

    /// Loads build cache
    pub fn load_cache(&mut self) -> Result<()> {
        debug!("Loading cache");
        let path = PathBuf::from(&self.options.prefix).join("cache");
        let reader = fs::File::open(path).map(|f| BufReader::new(f));

        if let Ok(reader) = reader {
            for line in reader.lines() {
                self.cache.insert(line?);
            }
        }

        self.load_database_cache()?;

        Ok(())
    }

    fn load_database_cache(&mut self) -> Result<()> {
        debug!("Loading database cache");
        use db::connect_db;
        let conn = connect_db()?;

        for row in &conn.query("SELECT name, version FROM crates, releases \
                               WHERE crates.id = releases.crate_id",
                   &[])
            .unwrap() {
            let name: String = row.get(0);
            let version: String = row.get(1);
            self.db_cache.insert(format!("{}-{}", name, version));
        }

        Ok(())
    }

    /// Saves build cache
    pub fn save_cache(&self) -> Result<()> {
        debug!("Saving cache");
        let path = PathBuf::from(&self.options.prefix).join("cache");
        let mut file = fs::OpenOptions::new()
            .write(true)
            .create(true)
            .open(path)?;
        for krate in &self.cache {
            writeln!(file, "{}", krate)?;
        }
        Ok(())
    }

    fn lock_path(&self) -> PathBuf {
        self.options.prefix.join("cratesfyi.lock")
    }

    /// Creates a lock file. Daemon will check this lock file and stop operating if its exists.
    pub fn lock(&self) -> Result<()> {
        let path = self.lock_path();
        if !path.exists() {
            fs::OpenOptions::new().write(true).create(true).open(path)?;
        }
        Ok(())
    }

    /// Removes lock file.
    pub fn unlock(&self) -> Result<()> {
        let path = self.lock_path();
        if path.exists() {
            fs::remove_file(path)?;
        }
        Ok(())
    }

    /// Checks for the lock file and returns whether it currently exists.
    pub fn is_locked(&self) -> bool {
        self.lock_path().exists()
    }

    /// Returns a reference of options
    pub fn options(&self) -> &DocBuilderOptions {
        &self.options
    }

    fn add_to_cache(&mut self, name: &str, version: &str) {
        self.cache.insert(format!("{}-{}", name, version));
    }

    fn should_build(&self, name: &str, version: &str) -> bool {
        let name = format!("{}-{}", name, version);
        let local = self.options.skip_if_log_exists && self.cache.contains(&name);
        let db = self.options.skip_if_exists && self.db_cache.contains(&name);
        !(local || db)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

pub use anyhow::{anyhow, bail, format_err, Error, Result};
use libra_types::{transaction::TransactionOutput, vm_error::VMStatus};
use thiserror::Error;

/// Defines all errors in this crate.
#[derive(Clone, Debug, Error)]
pub enum ErrorKind {
    #[error("an error occurred when executing the transaction")]
    VMExecutionFailure(TransactionOutput),
    #[error("the transaction was discarded")]
    DiscardedTransaction(TransactionOutput),
    #[error("the checker has failed to match the directives against the output")]
    CheckerFailure,
    #[error("VerificationError({0:?})")]
    VerificationError(VMStatus),
    #[error("other error: {0}")]
    #[allow(dead_code)]
    Other(String),
}
<commit_msg>[functional-tests] Print transaction status in functional-tests error message.<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

pub use anyhow::{anyhow, bail, format_err, Error, Result};
use libra_types::{transaction::TransactionOutput, vm_error::VMStatus};
use thiserror::Error;

/// Defines all errors in this crate.
#[derive(Clone, Debug, Error)]
pub enum ErrorKind {
    #[error("an error occurred when executing the transaction, txn status {:?}", .0.status())]
    VMExecutionFailure(TransactionOutput),
    #[error("the transaction was discarded")]
    DiscardedTransaction(TransactionOutput),
    #[error("the checker has failed to match the directives against the output")]
    CheckerFailure,
    #[error("VerificationError({0:?})")]
    VerificationError(VMStatus),
    #[error("other error: {0}")]
    #[allow(dead_code)]
    Other(String),
}
<|endoftext|>