<commit_before>// Copyright (c) 2016-2018 The http-serve developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE.txt or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT.txt or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use futures_channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
use futures_util::{future, StreamExt};
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::io::{self, Write};
use std::sync::Mutex;

type BoxedError = Box<dyn std::error::Error + Send + Sync>;

async fn serve(req: http::Request<hyper::Body>) -> Result<http::Response<hyper::Body>, BoxedError> {
    let cmds = CMDS.lock().unwrap().remove(req.uri().path()).unwrap();
    let (resp, w) = http_serve::streaming_body(&req).build();
    let mut w = w.unwrap();
    tokio::spawn(cmds.for_each(move |cmd| {
        match cmd {
            Cmd::WriteAll(s) => w.write_all(s).unwrap(),
            Cmd::Abort(e) => w.abort(e),
            Cmd::Flush => w.flush().unwrap(),
        }
        future::ready(())
    }));
    Ok(resp)
}

#[derive(Debug)]
enum Cmd {
    WriteAll(&'static [u8]),
    Flush,
    Abort(Box<dyn std::error::Error + Send + Sync>),
}

struct Server {
    addr: String,
}

fn new_server() -> Server {
    let (server_tx, server_rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        let make_svc = hyper::service::make_service_fn(|_conn| {
            future::ok::<_, hyper::Error>(hyper::service::service_fn(serve))
        });
        let rt = tokio::runtime::Runtime::new().unwrap();
        let _guard = rt.enter();

        let addr = ([127, 0, 0, 1], 0).into();
        let srv = hyper::Server::bind(&addr).serve(make_svc);
        let addr = srv.local_addr();
        server_tx
            .send(Server {
                addr: format!("http://{}:{}", addr.ip(), addr.port()),
            })
            .unwrap();
        rt.block_on(srv).unwrap();
    });
    server_rx.recv().unwrap()
}

static SERVER: Lazy<Server> = Lazy::new(new_server);
static CMDS: Lazy<Mutex<HashMap<&'static str, UnboundedReceiver<Cmd>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

fn setup_req(
    path: &'static str,
    auto_gzip: bool,
) -> (UnboundedSender<Cmd>, reqwest::RequestBuilder) {
    let (tx, rx) = mpsc::unbounded();
    CMDS.lock().unwrap().insert(path, rx);
    let client = reqwest::Client::builder().gzip(auto_gzip).build().unwrap();
    let req = client.get(&format!("{}{}", SERVER.addr, path));
    (tx, req)
}

async fn basic(path: &'static str, auto_gzip: bool) {
    let _ = env_logger::try_init();
    let (cmds, req) = setup_req(path, auto_gzip);
    let resp = req.send().await.unwrap();

    cmds.unbounded_send(Cmd::WriteAll(b"1234")).unwrap();
    cmds.unbounded_send(Cmd::WriteAll(b"5678")).unwrap();
    drop(cmds);
    assert_eq!(None, resp.headers().get(reqwest::header::CONTENT_ENCODING));
    let buf = resp.bytes().await.unwrap();
    assert_eq!(b"12345678", &buf[..]);
}

#[tokio::test]
async fn no_gzip() {
    basic("/no_gzip", false).await;
}

#[tokio::test]
async fn auto_gzip() {
    basic("/auto_gzip", true).await;
}

async fn abort(path: &'static str, auto_gzip: bool) {
    let _ = env_logger::try_init();
    let (cmds, req) = setup_req(path, auto_gzip);
    let mut resp = req.send().await.unwrap();

    cmds.unbounded_send(Cmd::WriteAll(b"1234")).unwrap();
    cmds.unbounded_send(Cmd::Flush).unwrap();
    cmds.unbounded_send(Cmd::WriteAll(b"5678")).unwrap();
    let buf = resp.chunk().await.unwrap().unwrap();
    assert_eq!(b"1234", &buf[..]);

    cmds.unbounded_send(Cmd::Abort(Box::new(io::Error::new(
        io::ErrorKind::PermissionDenied, // note: not related to error kind below.
        "foo",
    ))))
    .unwrap();

    // This is fragile, but I don't see a better way to check that the error is as expected.
    let e = format!("{:?}", resp.chunk().await.unwrap_err());
    assert!(e.contains("UnexpectedEof"), e);
}

#[tokio::test]
async fn no_gzip_abort() {
    abort("/no_gzip_abort", false).await;
}

#[tokio::test]
async fn auto_gzip_abort() {
    abort("/auto_gzip_abort", true).await;
}

#[tokio::test]
async fn manual_gzip() {
    use reqwest::header;
    let _ = env_logger::try_init();
    let (cmds, req) = setup_req("/manual_gzip", false);
    let resp = req.header("Accept-Encoding", "gzip").send().await.unwrap();

    cmds.unbounded_send(Cmd::WriteAll(b"1234")).unwrap();
    drop(cmds);
    assert_eq!(
        resp.headers().get(header::CONTENT_ENCODING).unwrap(),
        "gzip"
    );
    let buf = resp.bytes().await.unwrap();
    assert_eq!(b"\x1f\x8b", &buf[..2]); // gzip magic number.
}
<commit_msg>address warning<commit_after>// Copyright (c) 2016-2018 The http-serve developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE.txt or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT.txt or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use futures_channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
use futures_util::{future, StreamExt};
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::io::{self, Write};
use std::sync::Mutex;

type BoxedError = Box<dyn std::error::Error + Send + Sync>;

async fn serve(req: http::Request<hyper::Body>) -> Result<http::Response<hyper::Body>, BoxedError> {
    let cmds = CMDS.lock().unwrap().remove(req.uri().path()).unwrap();
    let (resp, w) = http_serve::streaming_body(&req).build();
    let mut w = w.unwrap();
    tokio::spawn(cmds.for_each(move |cmd| {
        match cmd {
            Cmd::WriteAll(s) => w.write_all(s).unwrap(),
            Cmd::Abort(e) => w.abort(e),
            Cmd::Flush => w.flush().unwrap(),
        }
        future::ready(())
    }));
    Ok(resp)
}

#[derive(Debug)]
enum Cmd {
    WriteAll(&'static [u8]),
    Flush,
    Abort(Box<dyn std::error::Error + Send + Sync>),
}

struct Server {
    addr: String,
}

fn new_server() -> Server {
    let (server_tx, server_rx) = std::sync::mpsc::channel();
    std::thread::spawn(move || {
        let make_svc = hyper::service::make_service_fn(|_conn| {
            future::ok::<_, hyper::Error>(hyper::service::service_fn(serve))
        });
        let rt = tokio::runtime::Runtime::new().unwrap();
        let _guard = rt.enter();

        let addr = ([127, 0, 0, 1], 0).into();
        let srv = hyper::Server::bind(&addr).serve(make_svc);
        let addr = srv.local_addr();
        server_tx
            .send(Server {
                addr: format!("http://{}:{}", addr.ip(), addr.port()),
            })
            .unwrap();
        rt.block_on(srv).unwrap();
    });
    server_rx.recv().unwrap()
}

static SERVER: Lazy<Server> = Lazy::new(new_server);
static CMDS: Lazy<Mutex<HashMap<&'static str, UnboundedReceiver<Cmd>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

fn setup_req(
    path: &'static str,
    auto_gzip: bool,
) -> (UnboundedSender<Cmd>, reqwest::RequestBuilder) {
    let (tx, rx) = mpsc::unbounded();
    CMDS.lock().unwrap().insert(path, rx);
    let client = reqwest::Client::builder().gzip(auto_gzip).build().unwrap();
    let req = client.get(&format!("{}{}", SERVER.addr, path));
    (tx, req)
}

async fn basic(path: &'static str, auto_gzip: bool) {
    let _ = env_logger::try_init();
    let (cmds, req) = setup_req(path, auto_gzip);
    let resp = req.send().await.unwrap();

    cmds.unbounded_send(Cmd::WriteAll(b"1234")).unwrap();
    cmds.unbounded_send(Cmd::WriteAll(b"5678")).unwrap();
    drop(cmds);
    assert_eq!(None, resp.headers().get(reqwest::header::CONTENT_ENCODING));
    let buf = resp.bytes().await.unwrap();
    assert_eq!(b"12345678", &buf[..]);
}

#[tokio::test]
async fn no_gzip() {
    basic("/no_gzip", false).await;
}

#[tokio::test]
async fn auto_gzip() {
    basic("/auto_gzip", true).await;
}

async fn abort(path: &'static str, auto_gzip: bool) {
    let _ = env_logger::try_init();
    let (cmds, req) = setup_req(path, auto_gzip);
    let mut resp = req.send().await.unwrap();

    cmds.unbounded_send(Cmd::WriteAll(b"1234")).unwrap();
    cmds.unbounded_send(Cmd::Flush).unwrap();
    cmds.unbounded_send(Cmd::WriteAll(b"5678")).unwrap();
    let buf = resp.chunk().await.unwrap().unwrap();
    assert_eq!(b"1234", &buf[..]);

    cmds.unbounded_send(Cmd::Abort(Box::new(io::Error::new(
        io::ErrorKind::PermissionDenied, // note: not related to error kind below.
        "foo",
    ))))
    .unwrap();

    // This is fragile, but I don't see a better way to check that the error is as expected.
    let e = format!("{:?}", resp.chunk().await.unwrap_err());
    assert!(e.contains("UnexpectedEof"), "{}", e);
}

#[tokio::test]
async fn no_gzip_abort() {
    abort("/no_gzip_abort", false).await;
}

#[tokio::test]
async fn auto_gzip_abort() {
    abort("/auto_gzip_abort", true).await;
}

#[tokio::test]
async fn manual_gzip() {
    use reqwest::header;
    let _ = env_logger::try_init();
    let (cmds, req) = setup_req("/manual_gzip", false);
    let resp = req.header("Accept-Encoding", "gzip").send().await.unwrap();

    cmds.unbounded_send(Cmd::WriteAll(b"1234")).unwrap();
    drop(cmds);
    assert_eq!(
        resp.headers().get(header::CONTENT_ENCODING).unwrap(),
        "gzip"
    );
    let buf = resp.bytes().await.unwrap();
    assert_eq!(b"\x1f\x8b", &buf[..2]); // gzip magic number.
}
<|endoftext|>


<commit_before>use zookeeper::CreateMode::*;
use zookeeper::{WatchedEvent, ZooKeeper, ZooKeeperExt};
use zookeeper::acls::*;
use zookeeper::recipes::cache::PathChildrenCache;

use ZkCluster;

use std::sync::Arc;
use std::time::Duration;
use std::thread;
use env_logger;

#[test]
fn path_children_cache_test() {
    let _ = env_logger::init();

    // Create a test cluster
    let cluster = ZkCluster::start(1);

    // Connect to the test cluster
    let zk = Arc::new(ZooKeeper::connect(&cluster.connect_string,
                                         Duration::from_secs(30),
                                         |event: &WatchedEvent| info!("{:?}", event)).unwrap());

    zk.ensure_path("/cache").unwrap();
    zk.create("/cache/a", vec![1,4], OPEN_ACL_UNSAFE.clone(), Ephemeral).unwrap();
    zk.create("/cache/b", vec![2,4], OPEN_ACL_UNSAFE.clone(), Ephemeral).unwrap();
    zk.create("/cache/c", vec![3,4], OPEN_ACL_UNSAFE.clone(), Ephemeral).unwrap();

    let path_children_cache = Arc::new(PathChildrenCache::new(zk, "/cache").unwrap());

    let data = path_children_cache.get_current_data();

    info!("Data: {:?}", data);

    thread::sleep_ms(9999999);
}
<commit_msg>Update test_cache.rs<commit_after>use zookeeper::CreateMode::*;
use zookeeper::{WatchedEvent, ZooKeeper, ZooKeeperExt};
use zookeeper::acls::*;
use zookeeper::recipes::cache::PathChildrenCache;

use ZkCluster;

use std::sync::Arc;
use std::time::Duration;
use env_logger;

#[test]
fn path_children_cache_test() {
    let _ = env_logger::init();

    // Create a test cluster
    let cluster = ZkCluster::start(1);

    // Connect to the test cluster
    let zk = Arc::new(ZooKeeper::connect(&cluster.connect_string,
                                         Duration::from_secs(30),
                                         |event: &WatchedEvent| info!("{:?}", event)).unwrap());

    zk.ensure_path("/cache").unwrap();
    zk.create("/cache/a", vec![1,4], OPEN_ACL_UNSAFE.clone(), Ephemeral).unwrap();
    zk.create("/cache/b", vec![2,4], OPEN_ACL_UNSAFE.clone(), Ephemeral).unwrap();
    zk.create("/cache/c", vec![3,4], OPEN_ACL_UNSAFE.clone(), Ephemeral).unwrap();

    let path_children_cache = Arc::new(PathChildrenCache::new(zk, "/cache").unwrap());

    let data = path_children_cache.get_current_data();

    info!("Data: {:?}", data);
}
<|endoftext|>


<commit_before>//! `bless` updates the reference files in the repo with changed output files
//! from the last test run.

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::lazy::SyncLazy;
use std::path::PathBuf;
use walkdir::WalkDir;

use crate::clippy_project_root;

// NOTE: this is duplicated with tests/cargo/mod.rs What to do?
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
    Some(v) => v.into(),
    None => env::current_dir().unwrap().join("target"),
});

pub fn bless() {
    let test_dirs = [
        clippy_project_root().join("tests").join("ui"),
        clippy_project_root().join("tests").join("ui-toml"),
        clippy_project_root().join("tests").join("ui-cargo"),
    ];
    for test_dir in &test_dirs {
        WalkDir::new(test_dir)
            .into_iter()
            .filter_map(Result::ok)
            .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
            .for_each(|f| {
                update_reference_file(f.path().with_extension("stdout"));
                update_reference_file(f.path().with_extension("stderr"));
                update_reference_file(f.path().with_extension("fixed"));
            });
    }
}

fn update_reference_file(reference_file_path: PathBuf) {
    let test_output_path = build_dir().join(PathBuf::from(reference_file_path.file_name().unwrap()));
    let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();

    // If compiletest did not write any changes during the test run,
    // we don't have to update anything
    if !test_output_path.exists() {
        return;
    }

    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
    let reference_file = fs::read(&reference_file_path).unwrap_or_default();

    if test_output_file != reference_file {
        // If a test run caused an output file to change, update the reference file
        println!("updating {}", &relative_reference_file_path.display());
        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");

        // We need to re-read the file now because it was potentially updated from copying
        let reference_file = fs::read(&reference_file_path).unwrap_or_default();

        if reference_file.is_empty() {
            // If we copied over an empty output file, we remove the now empty reference file
            println!("removing {}", &relative_reference_file_path.display());
            fs::remove_file(reference_file_path).expect("Could not remove reference file");
        }
    }
}

fn build_dir() -> PathBuf {
    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
    let mut path = PathBuf::new();
    path.push(CARGO_TARGET_DIR.clone());
    path.push(profile);
    path.push("test_build_base");
    path
}
<commit_msg>Auto merge of #6525 - phansch:fix-bless-in-subdirs, r=flip1995<commit_after>//! `bless` updates the reference files in the repo with changed output files
//! from the last test run.

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::lazy::SyncLazy;
use std::path::PathBuf;
use walkdir::WalkDir;

use crate::clippy_project_root;

// NOTE: this is duplicated with tests/cargo/mod.rs What to do?
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
    Some(v) => v.into(),
    None => env::current_dir().unwrap().join("target"),
});

pub fn bless() {
    let test_suite_dirs = [
        clippy_project_root().join("tests").join("ui"),
        clippy_project_root().join("tests").join("ui-toml"),
        clippy_project_root().join("tests").join("ui-cargo"),
    ];
    for test_suite_dir in &test_suite_dirs {
        WalkDir::new(test_suite_dir)
            .into_iter()
            .filter_map(Result::ok)
            .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
            .for_each(|f| {
                let test_name = f.path().strip_prefix(test_suite_dir).unwrap();

                update_reference_file(f.path().with_extension("stdout"), test_name.with_extension("stdout"));
                update_reference_file(f.path().with_extension("stderr"), test_name.with_extension("stderr"));
                update_reference_file(f.path().with_extension("fixed"), test_name.with_extension("fixed"));
            });
    }
}

fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf) {
    let test_output_path = build_dir().join(test_name);
    let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();

    // If compiletest did not write any changes during the test run,
    // we don't have to update anything
    if !test_output_path.exists() {
        return;
    }

    let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
    let reference_file = fs::read(&reference_file_path).unwrap_or_default();

    if test_output_file != reference_file {
        // If a test run caused an output file to change, update the reference file
        println!("updating {}", &relative_reference_file_path.display());
        fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");

        // We need to re-read the file now because it was potentially updated from copying
        let reference_file = fs::read(&reference_file_path).unwrap_or_default();

        if reference_file.is_empty() {
            // If we copied over an empty output file, we remove the now empty reference file
            println!("removing {}", &relative_reference_file_path.display());
            fs::remove_file(reference_file_path).expect("Could not remove reference file");
        }
    }
}

fn build_dir() -> PathBuf {
    let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
    let mut path = PathBuf::new();
    path.push(CARGO_TARGET_DIR.clone());
    path.push(profile);
    path.push("test_build_base");
    path
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#![feature(try_from)]
extern crate bincode;
extern crate cita_crypto as crypto;
extern crate clap;
extern crate common_types;
extern crate core;
extern crate cpuprofiler;
extern crate dotenv;
#[macro_use]
extern crate libproto;
extern crate proof;
extern crate protobuf;
extern crate rustc_serialize;
extern crate util;

#[macro_use]
extern crate log;
extern crate logger;
extern crate pubsub;
extern crate rlp;
#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

mod generate_block;

use std::collections::HashMap;
use std::convert::{From, TryFrom};
use std::fs;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};
use std::time;

use clap::App;

use crypto::{CreateKey, KeyPair, PrivKey};
use generate_block::BuildBlock;
use libproto::Message;
use libproto::router::{MsgType, RoutingKey, SubModules};
use pubsub::start_pubsub;
use util::{H256, U256};

pub type PubType = (String, Vec<u8>);

const GENESIS_TIMESTAMP: u64 = 1524000000;

// Build the block from transactions, then send it to MQ
fn send_block(
    pre_hash: H256,
    height: u64,
    pub_sender: Sender<PubType>,
    sys_time: Arc<Mutex<time::SystemTime>>,
    mock_block: &serde_yaml::Value,
    privkey: &PrivKey,
) {
    use libproto::SignedTransaction;

    let txs: Vec<SignedTransaction> = mock_block["transactions"]
        .as_sequence()
        .unwrap()
        .iter()
        .map(|tx| {
            let contract_address = tx["to"].as_str().unwrap();
            let tx_privkey_str = tx["privkey"].as_str().unwrap();
            let tx_privkey: PrivKey = PrivKey::from_any_str(tx_privkey_str).unwrap();
            let data = tx["data"].as_str().unwrap();
            let quota = tx["quota"].as_u64().unwrap();
            let nonce = tx["nonce"].as_u64().unwrap() as u32;
            let valid_until_block = tx["valid_until_block"].as_u64().unwrap();

            let sender = KeyPair::from_privkey(*privkey).unwrap().address().clone();
            info!(
                "sender={}, contract_address={}",
                sender.hex(),
                BuildBlock::build_contract_address(&sender, &U256::from(nonce)).hex()
            );
            info!(
                "address={}, quota={}, nonce={}",
                contract_address, quota, nonce
            );
            BuildBlock::build_tx(
                contract_address,
                data,
                quota,
                nonce,
                valid_until_block,
                &tx_privkey,
            )
        })
        .collect();

    // 构造block
    let (send_data, _block) = BuildBlock::build_block_with_proof(
        &txs,
        pre_hash,
        height,
        privkey,
        GENESIS_TIMESTAMP + height * 3,
    );
    info!(
        "===============send block ({} transactions)===============",
        txs.len()
    );
    (*sys_time.lock().unwrap()) = time::SystemTime::now();
    pub_sender
        .send((
            routing_key!(Consensus >> BlockWithProof).into(),
            send_data.clone(),
        ))
        .unwrap();
}

fn main() {
    logger::init();
    info!("CITA:Chain executor mock");

    let matches = App::new("Chain executor mock")
        .version("0.1")
        .author("Cryptape")
        .arg(
            clap::Arg::with_name("mock-data")
                .short("m")
                .long("mock-data")
                .required(true)
                .takes_value(true)
                .help("YAML format mock data"),
        )
        .get_matches();

    let mock_data_path = matches.value_of("mock-data").unwrap();
    let mut mock_data_string = String::new();
    fs::File::open(mock_data_path)
        .expect("Open mock data file error")
        .read_to_string(&mut mock_data_string)
        .expect("Read mock data file error");
    let mut mock_data: serde_yaml::Value =
        serde_yaml::from_str(mock_data_string.as_str()).expect("Parse mock data error");

    info!("mock-data-path={}", mock_data_path);
    let (tx_sub, rx_sub) = channel();
    let (tx_pub, rx_pub) = channel();

    start_pubsub(
        "consensus",
        routing_key!([Chain >> RichStatus]),
        tx_sub,
        rx_pub,
    );
    let amqp_url = std::env::var("AMQP_URL").expect("AMQP_URL empty");
    info!("AMQP_URL={}", amqp_url);
    let sys_time = Arc::new(Mutex::new(time::SystemTime::now()));

    let privkey: PrivKey = {
        let privkey_str = mock_data["privkey"].as_str().unwrap();
        PrivKey::from_any_str(privkey_str).unwrap()
    };
    let mut mock_blocks: HashMap<u64, &serde_yaml::Value> = HashMap::new();
    for block in mock_data["blocks"].as_sequence_mut().unwrap().into_iter() {
        let block_number = block["number"].as_u64().unwrap();
        mock_blocks.insert(block_number, block);
    }
    {
        let mut numbers = mock_blocks.keys().collect::<Vec<&u64>>();
        numbers.sort();
        info!(">> numbers: {:?}", numbers);
    }
    for number in 1..(mock_blocks.len() as u64 + 1) {
        if !mock_blocks.contains_key(&number) {
            error!("Block missing, number={}", number);
            return;
        }
    }

    loop {
        let (key, body) = rx_sub.recv().unwrap();
        info!("received: key={}", key);
        let mut msg = Message::try_from(&body).unwrap();
        match RoutingKey::from(&key) {
            // 接受 chain 发送的 authorities_list
            routing_key!(Chain >> RichStatus) => {
                let rich_status = msg.take_rich_status().unwrap();
                let height = rich_status.height + 1;
                if let Some(mock_block) = mock_blocks.remove(&height) {
                    info!(
                        "send consensus block rich_status.height={} height = {:?}",
                        rich_status.height, height
                    );
                    send_block(
                        H256::from_slice(&rich_status.hash),
                        height,
                        tx_pub.clone(),
                        sys_time.clone(),
                        &mock_block,
                        &privkey,
                    );
                } else {
                    warn!("No data for this block height = {:?}", height);
                };
                if mock_blocks.is_empty() {
                    break;
                }
            }
            _ => (),
        }
    }
    info!("[[DONE]]");
}
<commit_msg>Mock data may not generate chain data, may be a bug<commit_after>// CITA
// Copyright 2016-2017 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#![feature(try_from)]
extern crate bincode;
extern crate cita_crypto as crypto;
extern crate clap;
extern crate common_types;
extern crate core;
extern crate cpuprofiler;
extern crate dotenv;
#[macro_use]
extern crate libproto;
extern crate proof;
extern crate protobuf;
extern crate rustc_serialize;
extern crate util;

#[macro_use]
extern crate log;
extern crate logger;
extern crate pubsub;
extern crate rlp;
#[macro_use]
extern crate serde_derive;
extern crate serde_yaml;

mod generate_block;

use std::collections::HashMap;
use std::convert::{From, TryFrom};
use std::fs;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};
use std::time;

use clap::App;

use crypto::{CreateKey, KeyPair, PrivKey};
use generate_block::BuildBlock;
use libproto::Message;
use libproto::router::{MsgType, RoutingKey, SubModules};
use pubsub::start_pubsub;
use util::{H256, U256};

pub type PubType = (String, Vec<u8>);

const GENESIS_TIMESTAMP: u64 = 1524000000;

// Build the block from transactions, then send it to MQ
fn send_block(
    pre_hash: H256,
    height: u64,
    pub_sender: Sender<PubType>,
    sys_time: Arc<Mutex<time::SystemTime>>,
    mock_block: &serde_yaml::Value,
    privkey: &PrivKey,
) {
    use libproto::SignedTransaction;

    let txs: Vec<SignedTransaction> = mock_block["transactions"]
        .as_sequence()
        .unwrap()
        .iter()
        .map(|tx| {
            let contract_address = tx["to"].as_str().unwrap();
            let tx_privkey_str = tx["privkey"].as_str().unwrap();
            let tx_privkey: PrivKey = PrivKey::from_any_str(tx_privkey_str).unwrap();
            let data = tx["data"].as_str().unwrap();
            let quota = tx["quota"].as_u64().unwrap();
            let nonce = tx["nonce"].as_u64().unwrap() as u32;
            let valid_until_block = tx["valid_until_block"].as_u64().unwrap();

            let sender = KeyPair::from_privkey(*privkey).unwrap().address().clone();
            info!(
                "sender={}, contract_address={}",
                sender.hex(),
                BuildBlock::build_contract_address(&sender, &U256::from(nonce)).hex()
            );
            info!(
                "address={}, quota={}, nonce={}",
                contract_address, quota, nonce
            );
            BuildBlock::build_tx(
                contract_address,
                data,
                quota,
                nonce,
                valid_until_block,
                &tx_privkey,
            )
        })
        .collect();

    // 构造block
    let (send_data, _block) = BuildBlock::build_block_with_proof(
        &txs,
        pre_hash,
        height,
        privkey,
        GENESIS_TIMESTAMP + height * 3,
    );
    info!(
        "===============send block ({} transactions)===============",
        txs.len()
    );
    (*sys_time.lock().unwrap()) = time::SystemTime::now();
    pub_sender
        .send((
            routing_key!(Consensus >> BlockWithProof).into(),
            send_data.clone(),
        ))
        .unwrap();
}

fn main() {
    logger::init();
    info!("CITA:Chain executor mock");

    let matches = App::new("Chain executor mock")
        .version("0.1")
        .author("Cryptape")
        .arg(
            clap::Arg::with_name("mock-data")
                .short("m")
                .long("mock-data")
                .required(true)
                .takes_value(true)
                .help("YAML format mock data"),
        )
        .get_matches();

    let mock_data_path = matches.value_of("mock-data").unwrap();
    let mut mock_data_string = String::new();
    fs::File::open(mock_data_path)
        .expect("Open mock data file error")
        .read_to_string(&mut mock_data_string)
        .expect("Read mock data file error");
    let mut mock_data: serde_yaml::Value =
        serde_yaml::from_str(mock_data_string.as_str()).expect("Parse mock data error");

    info!("mock-data-path={}", mock_data_path);
    let (tx_sub, rx_sub) = channel();
    let (tx_pub, rx_pub) = channel();

    start_pubsub(
        "consensus",
        routing_key!([Chain >> RichStatus]),
        tx_sub,
        rx_pub,
    );
    let amqp_url = std::env::var("AMQP_URL").expect("AMQP_URL empty");
    info!("AMQP_URL={}", amqp_url);
    let sys_time = Arc::new(Mutex::new(time::SystemTime::now()));

    let privkey: PrivKey = {
        let privkey_str = mock_data["privkey"].as_str().unwrap();
        PrivKey::from_any_str(privkey_str).unwrap()
    };
    let mut mock_blocks: HashMap<u64, &serde_yaml::Value> = HashMap::new();
    for block in mock_data["blocks"].as_sequence_mut().unwrap().into_iter() {
        let block_number = block["number"].as_u64().unwrap();
        mock_blocks.insert(block_number, block);
    }
    {
        let mut numbers = mock_blocks.keys().collect::<Vec<&u64>>();
        numbers.sort();
        info!(">> numbers: {:?}", numbers);
    }
    for number in 1..(mock_blocks.len() as u64 + 1) {
        if !mock_blocks.contains_key(&number) {
            error!("Block missing, number={}", number);
            return;
        }
    }
    let mut repeat = 0u8;
    let mut _current_height = 0u8;

    loop {
        let (key, body) = rx_sub.recv().unwrap();
        info!("received: key={}", key);
        let mut msg = Message::try_from(&body).unwrap();
        match RoutingKey::from(&key) {
            // 接受 chain 发送的 authorities_list
            routing_key!(Chain >> RichStatus) => {
                let rich_status = msg.take_rich_status().unwrap();
                let height = rich_status.height + 1;

                if let Some(_) = mock_blocks.remove(&rich_status.height) {
                    _current_height = rich_status.height as u8;
                    repeat = 0;
                } else {
                    repeat += 1;
                }

                if repeat >= 3 {
                    warn!("the {} block can't generate", height);
                }

                if let Some(mock_block) = mock_blocks.get(&height) {
                    info!(
                        "send consensus block rich_status.height={} height = {:?}",
                        rich_status.height, height
                    );
                    send_block(
                        H256::from_slice(&rich_status.hash),
                        height,
                        tx_pub.clone(),
                        sys_time.clone(),
                        &mock_block,
                        &privkey,
                    );
                } else {
                    warn!("No data for this block height = {:?}", height);
                };
                if mock_blocks.is_empty() {
                    break;
                }
            }
            _ => (),
        }
    }
    info!("[[DONE]]");
}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate slog;

use slog::Drain;
use smithay::{
    backend::drm::{
        common::Error,
        device_bind,
        legacy::{LegacyDrmDevice, LegacyDrmSurface},
        Device, DeviceHandler, RawSurface, Surface,
    },
    reexports::{
        calloop::EventLoop,
        drm::{
            buffer::format::PixelFormat,
            control::{
                connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer,
                Device as ControlDevice,
            },
        },
    },
};
use std::{
    fs::{File, OpenOptions},
    io::Error as IoError,
    rc::Rc,
    sync::Mutex,
};

fn main() {
    let log = slog::Logger::root(Mutex::new(slog_term::term_full().fuse()).fuse(), o!());

    /*
     * Initialize the drm backend
     */

    // "Find" a suitable drm device
    let mut options = OpenOptions::new();
    options.read(true);
    options.write(true);
    let mut device = LegacyDrmDevice::new(options.open("/dev/dri/card0").unwrap(), log.clone()).unwrap();

    // Get a set of all modesetting resource handles (excluding planes):
    let res_handles = Device::resource_handles(&device).unwrap();

    // Use first connected connector
    let connector_info = res_handles
        .connectors()
        .iter()
        .map(|conn| device.get_connector_info(*conn).unwrap())
        .find(|conn| conn.state() == ConnectorState::Connected)
        .unwrap();

    // Use the first encoder
    let encoder = connector_info
        .encoders()
        .iter()
        .filter_map(|&e| e)
        .next()
        .unwrap();
    let encoder_info = device.get_encoder_info(encoder).unwrap();

    // use the connected crtc if any
    let crtc = encoder_info
        .crtc()
        // or use the first one that is compatible with the encoder
        .unwrap_or_else(|| {
            *res_handles
                .filter_crtcs(encoder_info.possible_crtcs())
                .iter()
                .next()
                .unwrap()
        });

    // Assuming we found a good connector and loaded the info into `connector_info`
    let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)

    // Initialize the hardware backend
    let surface = Rc::new(device.create_surface(crtc).unwrap());

    surface.use_mode(Some(mode)).unwrap();
    for conn in surface.current_connectors().into_iter() {
        if conn != connector_info.handle() {
            surface.remove_connector(conn).unwrap();
        }
    }
    surface.add_connector(connector_info.handle()).unwrap();

    /*
     * Lets create buffers and framebuffers.
     * We use drm-rs DumbBuffers, because they always work and require little to no setup.
     * But they are very slow, this is just for demonstration purposes.
     */
    let (w, h) = mode.size();
    let front_buffer = device
        .create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
        .unwrap();
    let front_framebuffer = device.add_framebuffer(&front_buffer).unwrap();
    let back_buffer = device
        .create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
        .unwrap();
    let back_framebuffer = device.add_framebuffer(&back_buffer).unwrap();

    device.set_handler(DrmHandlerImpl {
        current: front_framebuffer,
        front: (front_buffer, front_framebuffer),
        back: (back_buffer, back_framebuffer),
        surface: surface.clone(),
    });

    /*
     * Register the DrmDevice on the EventLoop
     */
    let mut event_loop = EventLoop::<()>::new().unwrap();
    let _source = device_bind(&event_loop.handle(), device)
        .map_err(|err| -> IoError { err.into() })
        .unwrap();

    // Start rendering
    if surface.commit_pending() {
        surface.commit(front_framebuffer).unwrap();
    }
    RawSurface::page_flip(&*surface, front_framebuffer).unwrap();

    // Run
    event_loop.run(None, &mut (), |_| {}).unwrap();
}

pub struct DrmHandlerImpl {
    front: (DumbBuffer, framebuffer::Handle),
    back: (DumbBuffer, framebuffer::Handle),
    current: framebuffer::Handle,
    surface: Rc<LegacyDrmSurface<File>>,
}

impl DeviceHandler for DrmHandlerImpl {
    type Device = LegacyDrmDevice<File>;

    fn vblank(&mut self, _crtc: crtc::Handle) {
        {
            // Swap and map buffer
            let mut mapping = if self.current == self.front.1 {
                self.current = self.back.1;
                self.surface.map_dumb_buffer(&mut self.back.0).unwrap()
            } else {
                self.current = self.front.1;
                self.surface.map_dumb_buffer(&mut self.front.0).unwrap()
            };

            // now we could render to the mapping via software rendering.
            // this example just sets some grey color

            for x in mapping.as_mut() {
                *x = 128;
            }
        }
        RawSurface::page_flip(&*self.surface, self.current).unwrap();
    }

    fn error(&mut self, error: Error) {
        panic!("{:?}", error);
    }
}
<commit_msg>fixup raw_legacy flip after commit<commit_after>#![warn(rust_2018_idioms)]

#[macro_use]
extern crate slog;

use slog::Drain;
use smithay::{
    backend::drm::{
        common::Error,
        device_bind,
        legacy::{LegacyDrmDevice, LegacyDrmSurface},
        Device, DeviceHandler, RawSurface, Surface,
    },
    reexports::{
        calloop::EventLoop,
        drm::{
            buffer::format::PixelFormat,
            control::{
                connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer,
                Device as ControlDevice,
            },
        },
    },
};
use std::{
    fs::{File, OpenOptions},
    io::Error as IoError,
    rc::Rc,
    sync::Mutex,
};

fn main() {
    let log = slog::Logger::root(Mutex::new(slog_term::term_full().fuse()).fuse(), o!());

    /*
     * Initialize the drm backend
     */

    // "Find" a suitable drm device
    let mut options = OpenOptions::new();
    options.read(true);
    options.write(true);
    let mut device = LegacyDrmDevice::new(options.open("/dev/dri/card0").unwrap(), log.clone()).unwrap();

    // Get a set of all modesetting resource handles (excluding planes):
    let res_handles = Device::resource_handles(&device).unwrap();

    // Use first connected connector
    let connector_info = res_handles
        .connectors()
        .iter()
        .map(|conn| device.get_connector_info(*conn).unwrap())
        .find(|conn| conn.state() == ConnectorState::Connected)
        .unwrap();

    // Use the first encoder
    let encoder = connector_info
        .encoders()
        .iter()
        .filter_map(|&e| e)
        .next()
        .unwrap();
    let encoder_info = device.get_encoder_info(encoder).unwrap();

    // use the connected crtc if any
    let crtc = encoder_info
        .crtc()
        // or use the first one that is compatible with the encoder
        .unwrap_or_else(|| {
            *res_handles
                .filter_crtcs(encoder_info.possible_crtcs())
                .iter()
                .next()
                .unwrap()
        });

    // Assuming we found a good connector and loaded the info into `connector_info`
    let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)

    // Initialize the hardware backend
    let surface = Rc::new(device.create_surface(crtc).unwrap());

    surface.use_mode(Some(mode)).unwrap();
    for conn in surface.current_connectors().into_iter() {
        if conn != connector_info.handle() {
            surface.remove_connector(conn).unwrap();
        }
    }
    surface.add_connector(connector_info.handle()).unwrap();

    /*
     * Lets create buffers and framebuffers.
     * We use drm-rs DumbBuffers, because they always work and require little to no setup.
     * But they are very slow, this is just for demonstration purposes.
     */
    let (w, h) = mode.size();
    let front_buffer = device
        .create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
        .unwrap();
    let front_framebuffer = device.add_framebuffer(&front_buffer).unwrap();
    let back_buffer = device
        .create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
        .unwrap();
    let back_framebuffer = device.add_framebuffer(&back_buffer).unwrap();

    device.set_handler(DrmHandlerImpl {
        current: front_framebuffer,
        front: (front_buffer, front_framebuffer),
        back: (back_buffer, back_framebuffer),
        surface: surface.clone(),
    });

    /*
     * Register the DrmDevice on the EventLoop
     */
    let mut event_loop = EventLoop::<()>::new().unwrap();
    let _source = device_bind(&event_loop.handle(), device)
        .map_err(|err| -> IoError { err.into() })
        .unwrap();

    // Start rendering
    if surface.commit_pending() {
        surface.commit(front_framebuffer).unwrap();
    }

    // Run
    event_loop.run(None, &mut (), |_| {}).unwrap();
}

pub struct DrmHandlerImpl {
    front: (DumbBuffer, framebuffer::Handle),
    back: (DumbBuffer, framebuffer::Handle),
    current: framebuffer::Handle,
    surface: Rc<LegacyDrmSurface<File>>,
}

impl DeviceHandler for DrmHandlerImpl {
    type Device = LegacyDrmDevice<File>;

    fn vblank(&mut self, _crtc: crtc::Handle) {
        {
            // Swap and map buffer
            let mut mapping = if self.current == self.front.1 {
                self.current = self.back.1;
                self.surface.map_dumb_buffer(&mut self.back.0).unwrap()
            } else {
                self.current = self.front.1;
                self.surface.map_dumb_buffer(&mut self.front.0).unwrap()
            };

            // now we could render to the mapping via software rendering.
            // this example just sets some grey color

            for x in mapping.as_mut() {
                *x = 128;
            }
        }
        RawSurface::page_flip(&*self.surface, self.current).unwrap();
    }

    fn error(&mut self, error: Error) {
        panic!("{:?}", error);
    }
}
<|endoftext|>


<commit_before>// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate open_aoe_drs as drs;
extern crate open_aoe_slp as slp;
extern crate open_aoe_palette as palette;

extern crate minifb;
extern crate clap;

use clap::{App, Arg};
use std::cmp;

use std::io;
use std::process;
use std::thread;
use std::time::Duration;

fn load_drs(file_name: &str) -> drs::DrsFile {
    println!("Loading DRS: {}", file_name);
    match drs::DrsFile::read_from_file(file_name) {
        Ok(result) => result,
        Err(err) => {
            println!("Failed to load DRS \"{}\": {}", file_name, err);
            process::exit(1);
        }
    }
}

struct Frame {
    width: usize,
    height: usize,
    buffer: Vec<u32>,
}

fn get_frame(slp: &slp::SlpFile, palette: &palette::Palette, frame_index: usize) -> Frame {
    let (mut width, mut height) = (0usize, 0usize);
    for shape in &slp.shapes {
        if shape.header.width as usize > width {
            width = shape.header.width as usize;
        }
        if shape.header.height as usize > height {
            height = shape.header.height as usize;
        }
    }

    let mut frame = Frame {
        width: width,
        height: height,
        buffer: vec![0; width * height],
    };

    let shape = &slp.shapes[frame_index];
    println!("Frame index {}: {:?}", frame_index, shape.header);
    for y in 0..(shape.header.height as usize) {
        for x in 0..(shape.header.width as usize) {
            let src_index = y * (shape.header.width as usize) + x;
            let palette_index = shape.pixels[src_index];
            let color = &palette[palette_index as usize];

            let dest_index = y * frame.width + x;
            frame.buffer[dest_index] = (color.r as u32) << 16 | (color.g as u32) << 8 | (color.b as u32);
        }
    }

    frame
}

fn main() {
    let matches = App::new("slp_viewer")
        .version("1.0")
        .author("Kevin Fuller <angered.ghandi@gmail.com>")
        .about("Shows SLP files from Age of Empires (1997)")
        .arg(Arg::with_name("DRS")
            .short("d")
            .long("drs")
            .value_name("DRS")
            .help("Sets which DRS file to load the SLP from")
            .takes_value(true))
        .arg(Arg::with_name("INTERFAC")
            .short("i")
            .long("interfac")
            .value_name("INTERFAC")
            .help("Sets location for interfac.drs (to get the palette from)")
            .takes_value(true))
        .arg(Arg::with_name("PLAYER")
            .short("p")
            .long("player")
            .value_name("PLAYER")
            .help("Sets the player color base index (must be in range 1 to 8, inclusive)")
            .takes_value(true))
        .arg(Arg::with_name("SLP")
            .help("SLP ID")
            .required(true)
            .index(1))
        .get_matches();

    let slp_id = matches.value_of("SLP").unwrap().parse::<u32>().expect("valid SLP ID");
    let drs_name = matches.value_of("DRS").unwrap_or("game/data/graphics.drs");
    let interfac_name = matches.value_of("INTERFAC").unwrap_or("game/data/interfac.drs");
    let mut player_index = matches.value_of("PLAYER")
        .unwrap_or("1")
        .parse::<u8>()
        .expect("valid player index in the range of 1 to 8 inclusive");

    if player_index > 8 {
        player_index = 8;
    } else if player_index == 0 {
        player_index = 1;
    }

    let slp_drs = load_drs(drs_name);
    let interfac_drs = load_drs(interfac_name);

    let slp_table = slp_drs.find_table(drs::DrsFileType::Slp)
        .expect(&format!("failed to find slp table in {}", drs_name));

    let slp_contents = match slp_table.find_file_contents(slp_id) {
        Some(contents) => contents,
        None => {
            println!("Couldn't find an SLP with ID {} in {}", slp_id, drs_name);
            process::exit(1);
        }
    };

    println!("Loading SLP: {}", slp_id);
    let slp = match slp::SlpFile::read_from(&mut io::Cursor::new(slp_contents), player_index) {
        Ok(result) => result,
        Err(err) => {
            println!("Failed to read SLP: {}", err);
            process::exit(1);
        }
    };

    println!("Loading palette");
    let bin_table = &interfac_drs.tables[0];
    let palette_contents = &bin_table.contents[26];
    let palette = match palette::read_from(&mut io::Cursor::new(palette_contents)) {
        Ok(palette) => palette,
        Err(err) => {
            println!("Failed to read palette: {}", err);
            process::exit(1);
        }
    };

    let mut frame_index: usize = 0;
    let mut current_frame = get_frame(&slp, &palette, frame_index);

    let mut window = match minifb::Window::new("slp_viewer",
                                               current_frame.width,
                                               current_frame.height,
                                               minifb::WindowOptions::default()) {
        Ok(win) => win,
        Err(err) => {
            println!("Failed to create window: {}", err);
            process::exit(1);
        }
    };

    while window.is_open() {
        window.update_with_buffer(&current_frame.buffer);
        thread::sleep(Duration::from_millis(100));

        let previous_frame_index = frame_index;
        if window.is_key_down(minifb::Key::Right) {
            frame_index += 1;
        } else if window.is_key_down(minifb::Key::Left) {
            frame_index = frame_index.saturating_sub(1);
        }
        frame_index = cmp::max(0, cmp::min(slp.shapes.len() - 1, frame_index));
        if previous_frame_index != frame_index {
            current_frame = get_frame(&slp, &palette, frame_index);
        }
    }
}
<commit_msg>Use value_t instead of parse::<u32> (#62)<commit_after>// OpenAOE: An open source reimplementation of Age of Empires (1997)
// Copyright (c) 2016 Kevin Fuller
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

extern crate open_aoe_drs as drs;
extern crate open_aoe_slp as slp;
extern crate open_aoe_palette as palette;

extern crate minifb;

#[macro_use(value_t)]
extern crate clap;

use clap::{App, Arg};
use std::cmp;

use std::io;
use std::process;
use std::thread;
use std::time::Duration;

fn load_drs(file_name: &str) -> drs::DrsFile {
    println!("Loading DRS: {}", file_name);
    match drs::DrsFile::read_from_file(file_name) {
        Ok(result) => result,
        Err(err) => {
            println!("Failed to load DRS \"{}\": {}", file_name, err);
            process::exit(1);
        }
    }
}

struct Frame {
    width: usize,
    height: usize,
    buffer: Vec<u32>,
}

fn get_frame(slp: &slp::SlpFile, palette: &palette::Palette, frame_index: usize) -> Frame {
    let (mut width, mut height) = (0usize, 0usize);
    for shape in &slp.shapes {
        if shape.header.width as usize > width {
            width = shape.header.width as usize;
        }
        if shape.header.height as usize > height {
            height = shape.header.height as usize;
        }
    }

    let mut frame = Frame {
        width: width,
        height: height,
        buffer: vec![0; width * height],
    };

    let shape = &slp.shapes[frame_index];
    println!("Frame index {}: {:?}", frame_index, shape.header);
    for y in 0..(shape.header.height as usize) {
        for x in 0..(shape.header.width as usize) {
            let src_index = y * (shape.header.width as usize) + x;
            let palette_index = shape.pixels[src_index];
            let color = &palette[palette_index as usize];

            let dest_index = y * frame.width + x;
            frame.buffer[dest_index] = (color.r as u32) << 16 | (color.g as u32) << 8 | (color.b as u32);
        }
    }

    frame
}

fn main() {
    let matches = App::new("slp_viewer")
        .version("1.0")
        .author("Kevin Fuller <angered.ghandi@gmail.com>")
        .about("Shows SLP files from Age of Empires (1997)")
        .arg(Arg::with_name("DRS")
            .short("d")
            .long("drs")
            .value_name("DRS")
            .help("Sets which DRS file to load the SLP from")
            .takes_value(true))
        .arg(Arg::with_name("INTERFAC")
            .short("i")
            .long("interfac")
            .value_name("INTERFAC")
            .help("Sets location for interfac.drs (to get the palette from)")
            .takes_value(true))
        .arg(Arg::with_name("PLAYER")
            .short("p")
            .long("player")
            .value_name("PLAYER")
            .help("Sets the player color base index (must be in range 1 to 8, inclusive)")
            .takes_value(true))
        .arg(Arg::with_name("SLP")
            .help("SLP ID")
            .required(true)
            .index(1))
        .get_matches();

    let slp_id = value_t!(matches, "SLP", u32).expect("valid SLP ID");
    let drs_name = matches.value_of("DRS").unwrap_or("game/data/graphics.drs");
    let interfac_name = matches.value_of("INTERFAC").unwrap_or("game/data/interfac.drs");
    let mut player_index = matches.value_of("PLAYER")
        .unwrap_or("1")
        .parse::<u8>()
        .expect("valid player index in the range of 1 to 8 inclusive");

    if player_index > 8 {
        player_index = 8;
    } else if player_index == 0 {
        player_index = 1;
    }

    let slp_drs = load_drs(drs_name);
    let interfac_drs = load_drs(interfac_name);

    let slp_table = slp_drs.find_table(drs::DrsFileType::Slp)
        .expect(&format!("failed to find slp table in {}", drs_name));

    let slp_contents = match slp_table.find_file_contents(slp_id) {
        Some(contents) => contents,
        None => {
            println!("Couldn't find an SLP with ID {} in {}", slp_id, drs_name);
            process::exit(1);
        }
    };

    println!("Loading SLP: {}", slp_id);
    let slp = match slp::SlpFile::read_from(&mut io::Cursor::new(slp_contents), player_index) {
        Ok(result) => result,
        Err(err) => {
            println!("Failed to read SLP: {}", err);
            process::exit(1);
        }
    };

    println!("Loading palette");
    let bin_table = &interfac_drs.tables[0];
    let palette_contents = &bin_table.contents[26];
    let palette = match palette::read_from(&mut io::Cursor::new(palette_contents)) {
        Ok(palette) => palette,
        Err(err) => {
            println!("Failed to read palette: {}", err);
            process::exit(1);
        }
    };

    let mut frame_index: usize = 0;
    let mut current_frame = get_frame(&slp, &palette, frame_index);

    let mut window = match minifb::Window::new("slp_viewer",
                                               current_frame.width,
                                               current_frame.height,
                                               minifb::WindowOptions::default()) {
        Ok(win) => win,
        Err(err) => {
            println!("Failed to create window: {}", err);
            process::exit(1);
        }
    };

    while window.is_open() {
        window.update_with_buffer(&current_frame.buffer);
        thread::sleep(Duration::from_millis(100));

        let previous_frame_index = frame_index;
        if window.is_key_down(minifb::Key::Right) {
            frame_index += 1;
        } else if window.is_key_down(minifb::Key::Left) {
            frame_index = frame_index.saturating_sub(1);
        }
        frame_index = cmp::max(0, cmp::min(slp.shapes.len() - 1, frame_index));
        if previous_frame_index != frame_index {
            current_frame = get_frame(&slp, &palette, frame_index);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Auto merge of #4201 - moz-gfx:github-sync, r=auto<commit_after><|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::fs;
use std::io::{BufRead, BufReader};
use std::net::{SocketAddr, TcpListener};
use std::path::PathBuf;
use std::process::{Command, Child, Stdio};
use std::thread;

use tempdir::TempDir;

/// A Kudu server node (either master or tablet server).
struct Node {
    name: String,
    bin: PathBuf,
    args: Vec<(&'static str, String)>,
    process: Option<Child>,
}

impl Node {
    fn new(name: String, bin: PathBuf, args: Vec<(&'static str, String)>) -> Node {
        Node {
            name: name,
            bin: bin,
            args: args,
            process: None,
        }

    }

    fn stop(&mut self) {
        let _ = self.process.take().expect(&format!("{} not running", &self.name)).kill();
    }

    fn start(&mut self) {
        assert!(self.process.is_none(), "{} already started", &self.name);

        let mut command = Command::new(&self.bin);

        for &(k, ref v) in &self.args {
            command.arg(format!("--{}={}", k, v));
        }

        command.stderr(Stdio::piped());
        let mut process = command.spawn().unwrap();
        let stderr = process.stderr.take().unwrap();

        let name = self.name.clone();
        thread::spawn(move || {
            let stderr = BufReader::new(stderr);
            for line in stderr.lines() {
                debug!("({}): {}", name, line.unwrap());
            }

        });
        self.process = Some(process);
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        let _ = self.process.take().map(|mut process| process.kill());
    }
}

pub struct MiniCluster {
    dir: TempDir,
    master_addrs: Vec<SocketAddr>,
    nodes: HashMap<SocketAddr, Node>,
}

impl MiniCluster {
    pub fn new(conf: &MiniClusterConfig) -> MiniCluster {
        let master_bin = get_executable_path("kudu-master");
        let tserver_bin = get_executable_path("kudu-tserver");
        let dir = TempDir::new("kudu-rs-mini-cluster").expect("unable to create temp dir");

        let num_nodes = (conf.num_masters + conf.num_tservers) as usize;
        let mut nodes = HashMap::with_capacity(num_nodes);

        let addrs = get_unbound_addresses(num_nodes);
        let (master_addrs, tserver_addrs) = addrs.split_at(conf.num_masters as usize);

        let master_addresses = master_addrs.iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
        let conf_args = conf.args();

        for (i, addr) in master_addrs.iter().enumerate() {
            let path = dir.path().join(format!("master-{}", i));
            let logs = dir.path().join(format!("master-{}-logs", i));
            fs::create_dir(&logs).expect("unable to create master log directory");

            let name = format!("master:{}", addr.port());

            let mut args = conf_args.clone();
            args.push(("fs_wal_dir", path.to_string_lossy().into_owned()));
            args.push(("fs_data_dirs", path.to_string_lossy().into_owned()));
            args.push(("log_dir", logs.to_string_lossy().into_owned()));
            args.push(("rpc_bind_addresses", addr.to_string()));
            args.push(("webserver_port", 0.to_string()));
            args.push(("logtostderr", true.to_string()));

            if conf.num_masters > 1 {
                args.push(("master_addresses", master_addresses.clone()));
            }

            let mut node = Node::new(name, master_bin.clone(), args);
            node.start();
            nodes.insert(*addr, node);
        }

        for (i, addr) in tserver_addrs.iter().enumerate() {
            let path = dir.path().join(format!("tserver-{}", i));
            let logs = dir.path().join(format!("tserver-{}-logs", i));
            fs::create_dir(&logs).expect("unable to create tserver log directory");

            let name = format!("tserver:{}", addr.port());

            let mut args = conf_args.clone();
            args.push(("fs_wal_dir", path.to_string_lossy().into_owned()));
            args.push(("fs_data_dirs", path.to_string_lossy().into_owned()));
            args.push(("log_dir", logs.to_string_lossy().into_owned()));
            args.push(("rpc_bind_addresses", addr.to_string()));
            args.push(("webserver_port", 0.to_string()));
            args.push(("logtostderr", true.to_string()));
            args.push(("tserver_master_addrs", master_addresses.clone()));

            let mut node = Node::new(name, tserver_bin.clone(), args);
            node.start();
            nodes.insert(*addr, node);
        }

        MiniCluster {
            dir: dir,
            master_addrs: master_addrs.to_owned(),
            nodes: nodes,
        }
    }

    pub fn master_addrs(&self) -> &[SocketAddr] {
        &self.master_addrs
    }

    pub fn stop_node(&mut self, addr: SocketAddr) {
        self.nodes.get_mut(&addr).expect(&format!("no node with address {}", addr)).stop();
    }

    pub fn start_node(&mut self, addr: SocketAddr) {
        self.nodes.get_mut(&addr).expect(&format!("no node with address {}", addr)).start();
    }
}

impl Default for MiniCluster {
    fn default() -> MiniCluster {
        MiniCluster::new(&MiniClusterConfig::default())
    }
}

pub fn get_unbound_address() -> SocketAddr {
    TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap()
}

/// Attempts to get local unbound socket addresses for testing.
fn get_unbound_addresses(count: usize) -> Vec<SocketAddr> {
    let mut listeners = Vec::with_capacity(count);
    let mut addrs = Vec::with_capacity(count);

    for _ in 0..count {
        let listener = TcpListener::bind("127.0.0.1:0").unwrap();
        let addr = listener.local_addr().unwrap();
        listeners.push(listener);
        addrs.push(addr);
    }
    addrs
}

/// Attempts to get the path of a Kudu executable (`kudu-master` or `kudu-tserver`). If the
/// `KUDU_HOME` environment variable is set, then that will be used, otherwise it will be searched
/// for on the path. If the executable can not be found, panic.
fn get_executable_path(executable: &str) -> PathBuf {
    if let Ok(kudu_home) = env::var("KUDU_HOME") {
        let mut bin = PathBuf::from(&kudu_home);
        bin.push("build");
        bin.push("latest");
        bin.push("bin");
        bin.push(executable);
        return bin;
    }

    let path_bytes = Command::new("which")
                             .arg(executable)
                             .output()
                             .expect(&format!("unable to find the {} executable. Set $KUDU_HOME or add it to $PATH",
                                              executable))
                             .stdout;
    let path = CString::new(path_bytes).unwrap().into_string().unwrap();

    PathBuf::from(path.lines().next().unwrap())
}

/// Mini cluster configuration options. Unless otherwise specified, the defaults match the master
/// and tablet server defaults.
pub struct MiniClusterConfig {
    /// The number of masters in the mini cluster. Default: 1.
    num_masters: i32,
    /// The number of tablet servers in the mini cluster. Default: 1.
    num_tservers: i32,

    // Logging Options

    /// Minimum logging level.
    min_log_level: Option<LogLevel>,

    /// Show all `VLOG(m)` messages for `m < this`. Overridden by `vmodule`.
    vlog: Option<i32>,

    /// Per-module `VLOG` level. List of (<module name>, <log level>) pairs. <module name> is a
    /// glob pattern, matched against the filename base (that is, name ignoring
    /// `.cc`/`.h`/`-inl.h`). <log level> overrides any value given by `vlog`.
    vmodule: Vec<(String, i32)>,

    /// If enabled, dump traces of all RPC negotiations to the log at `INFO` level.
    log_rpc_negotiation_trace: Option<bool>,

    /// If enabled, dump traces of all RPCs to the log at `INFO` level.
    log_rpc_trace: Option<bool>,

    // Latency Injection

    /// Amount of latency in milliseconds to inject into the RPC negotiation process.
    rpc_negotiation_delay: Option<i32>,

    /// Amount of latency in milliseconds to inject in GetTableLocations RPCs.
    get_table_locations_delay: Option<i32>,

    // Miscellaneous

    /// Whether to enable failure detection of tablet leaders. If enabled, attempts will be made to
    /// elect a follower as a new leader when the leader is detected to have failed.
    leader_failure_detection: Option<bool>,

    /// Whether to enable fsync() of data blocks, metadata, and their parent directories. Disabling
    /// this flag may cause data loss in the event of a system crash. Default: false.
    data_block_fsync: bool,
}

impl MiniClusterConfig {

    pub fn num_masters(&mut self, num_masters: i32) -> &mut MiniClusterConfig {
        self.num_masters = num_masters;
        self
    }

    pub fn num_tservers(&mut self, num_tservers: i32) -> &mut MiniClusterConfig {
        self.num_tservers = num_tservers;
        self
    }

    pub fn min_log_level(&mut self, log_level: LogLevel) -> &mut MiniClusterConfig {
        self.min_log_level = Some(log_level);
        self
    }

    pub fn vlog(&mut self, vlog_level: i32) -> &mut MiniClusterConfig {
        assert!(vlog_level >= 0);
        self.vlog = Some(vlog_level);
        self
    }

    pub fn vmodule(&mut self, module: String, vlog_level: i32) -> &mut MiniClusterConfig {
        assert!(vlog_level >= 0);
        self.vmodule.push((module, vlog_level));
        self
    }

    pub fn log_rpc_negotiation_trace(&mut self, log_rpc_negotiation_trace: bool) -> &mut MiniClusterConfig {
        self.log_rpc_negotiation_trace = Some(log_rpc_negotiation_trace);
        self
    }

    pub fn log_rpc_trace(&mut self, log_rpc_trace: bool) -> &mut MiniClusterConfig {
        self.log_rpc_trace = Some(log_rpc_trace);
        self
    }

    pub fn rpc_negotiation_delay(&mut self, millis: i32) -> &mut MiniClusterConfig {
        self.rpc_negotiation_delay = Some(millis);
        self
    }

    pub fn get_table_locations_delay(&mut self, millis: i32) -> &mut MiniClusterConfig {
        self.get_table_locations_delay = Some(millis);
        self
    }

    pub fn leader_failure_detection(&mut self, leader_failure_detection: bool) -> &mut MiniClusterConfig {
        self.leader_failure_detection = Some(leader_failure_detection);
        self
    }

    pub fn data_block_fsync(&mut self, data_block_fsync: bool) -> &mut MiniClusterConfig {
        self.data_block_fsync = data_block_fsync;
        self
    }

    fn args(&self) -> Vec<(&'static str, String)> {
        let mut args = Vec::new();

        if let Some(log_level) = self.min_log_level {
            args.push(("minloglevel", (log_level as usize).to_string()));
        }

        if let Some(vlog_level) = self.vlog {
            args.push(("v", vlog_level.to_string()));
        }

        if !self.vmodule.is_empty() {
            let modules = self.vmodule
                              .iter()
                              .map(|&(ref module, ref level)| format!("{}={}", module, level))
                              .collect::<Vec<_>>();
            args.push(("vmodule", modules.join(",")));
        }

        if let Some(log_rpc_negotiation_trace) = self.log_rpc_negotiation_trace {
            args.push(("rpc_trace_negotiation", log_rpc_negotiation_trace.to_string()));
        }

        if let Some(log_rpc_trace) = self.log_rpc_trace {
            args.push(("rpc_dump_all_traces", log_rpc_trace.to_string()));
        }

        if let Some(rpc_negotiation_delay) = self.rpc_negotiation_delay {
            args.push(("rpc_negotiation_inject_delay_ms", rpc_negotiation_delay.to_string()));
        }

        if let Some(get_table_locations_delay) = self.get_table_locations_delay {
            args.push(("master_inject_latency_on_tablet_lookup_ms",
                       get_table_locations_delay.to_string()));
        }

        if let Some(leader_failure_detection) = self.leader_failure_detection {
            args.push(("enable_leader_failure_detection",
                       leader_failure_detection.to_string()));
        }

        args.push(("enable_data_block_fsync",
                   self.data_block_fsync.to_string()));

        args
    }
}

impl Default for MiniClusterConfig {
    fn default() -> MiniClusterConfig {
        MiniClusterConfig {
            num_masters: 1,
            num_tservers: 1,
            min_log_level: None,
            vlog: None,
            vmodule: Vec::new(),
            log_rpc_negotiation_trace: None,
            log_rpc_trace: None,
            rpc_negotiation_delay: None,
            get_table_locations_delay: None,
            leader_failure_detection: None,
            data_block_fsync: false,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum LogLevel {
    Info = 0,
    Warning = 1,
    Error = 2,
    Fatal = 3,
}

#[cfg(test)]
mod tests {

    use env_logger;

    use super::*;

    #[test]
    fn test_spawn_mini_cluster() {
        let _ = env_logger::init();
        let _cluster = MiniCluster::default();
    }
}
<commit_msg>fix kudu binary not found message<commit_after>use std::collections::HashMap;
use std::env;
use std::ffi::CString;
use std::fs;
use std::io::{BufRead, BufReader};
use std::net::{SocketAddr, TcpListener};
use std::path::PathBuf;
use std::process::{Command, Child, Stdio};
use std::thread;

use tempdir::TempDir;

/// A Kudu server node (either master or tablet server).
struct Node {
    name: String,
    bin: PathBuf,
    args: Vec<(&'static str, String)>,
    process: Option<Child>,
}

impl Node {
    fn new(name: String, bin: PathBuf, args: Vec<(&'static str, String)>) -> Node {
        Node {
            name: name,
            bin: bin,
            args: args,
            process: None,
        }

    }

    fn stop(&mut self) {
        let _ = self.process.take().expect(&format!("{} not running", &self.name)).kill();
    }

    fn start(&mut self) {
        assert!(self.process.is_none(), "{} already started", &self.name);

        let mut command = Command::new(&self.bin);

        for &(k, ref v) in &self.args {
            command.arg(format!("--{}={}", k, v));
        }

        command.stderr(Stdio::piped());
        let mut process = command.spawn().unwrap();
        let stderr = process.stderr.take().unwrap();

        let name = self.name.clone();
        thread::spawn(move || {
            let stderr = BufReader::new(stderr);
            for line in stderr.lines() {
                debug!("({}): {}", name, line.unwrap());
            }

        });
        self.process = Some(process);
    }
}

impl Drop for Node {
    fn drop(&mut self) {
        let _ = self.process.take().map(|mut process| process.kill());
    }
}

pub struct MiniCluster {
    dir: TempDir,
    master_addrs: Vec<SocketAddr>,
    nodes: HashMap<SocketAddr, Node>,
}

impl MiniCluster {
    pub fn new(conf: &MiniClusterConfig) -> MiniCluster {
        let master_bin = get_executable_path("kudu-master");
        let tserver_bin = get_executable_path("kudu-tserver");
        let dir = TempDir::new("kudu-rs-mini-cluster").expect("unable to create temp dir");

        let num_nodes = (conf.num_masters + conf.num_tservers) as usize;
        let mut nodes = HashMap::with_capacity(num_nodes);

        let addrs = get_unbound_addresses(num_nodes);
        let (master_addrs, tserver_addrs) = addrs.split_at(conf.num_masters as usize);

        let master_addresses = master_addrs.iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
        let conf_args = conf.args();

        for (i, addr) in master_addrs.iter().enumerate() {
            let path = dir.path().join(format!("master-{}", i));
            let logs = dir.path().join(format!("master-{}-logs", i));
            fs::create_dir(&logs).expect("unable to create master log directory");

            let name = format!("master:{}", addr.port());

            let mut args = conf_args.clone();
            args.push(("fs_wal_dir", path.to_string_lossy().into_owned()));
            args.push(("fs_data_dirs", path.to_string_lossy().into_owned()));
            args.push(("log_dir", logs.to_string_lossy().into_owned()));
            args.push(("rpc_bind_addresses", addr.to_string()));
            args.push(("webserver_port", 0.to_string()));
            args.push(("logtostderr", true.to_string()));

            if conf.num_masters > 1 {
                args.push(("master_addresses", master_addresses.clone()));
            }

            let mut node = Node::new(name, master_bin.clone(), args);
            node.start();
            nodes.insert(*addr, node);
        }

        for (i, addr) in tserver_addrs.iter().enumerate() {
            let path = dir.path().join(format!("tserver-{}", i));
            let logs = dir.path().join(format!("tserver-{}-logs", i));
            fs::create_dir(&logs).expect("unable to create tserver log directory");

            let name = format!("tserver:{}", addr.port());

            let mut args = conf_args.clone();
            args.push(("fs_wal_dir", path.to_string_lossy().into_owned()));
            args.push(("fs_data_dirs", path.to_string_lossy().into_owned()));
            args.push(("log_dir", logs.to_string_lossy().into_owned()));
            args.push(("rpc_bind_addresses", addr.to_string()));
            args.push(("webserver_port", 0.to_string()));
            args.push(("logtostderr", true.to_string()));
            args.push(("tserver_master_addrs", master_addresses.clone()));

            let mut node = Node::new(name, tserver_bin.clone(), args);
            node.start();
            nodes.insert(*addr, node);
        }

        MiniCluster {
            dir: dir,
            master_addrs: master_addrs.to_owned(),
            nodes: nodes,
        }
    }

    pub fn master_addrs(&self) -> &[SocketAddr] {
        &self.master_addrs
    }

    pub fn stop_node(&mut self, addr: SocketAddr) {
        self.nodes.get_mut(&addr).expect(&format!("no node with address {}", addr)).stop();
    }

    pub fn start_node(&mut self, addr: SocketAddr) {
        self.nodes.get_mut(&addr).expect(&format!("no node with address {}", addr)).start();
    }
}

impl Default for MiniCluster {
    fn default() -> MiniCluster {
        MiniCluster::new(&MiniClusterConfig::default())
    }
}

pub fn get_unbound_address() -> SocketAddr {
    TcpListener::bind("127.0.0.1:0").unwrap().local_addr().unwrap()
}

/// Attempts to get local unbound socket addresses for testing.
fn get_unbound_addresses(count: usize) -> Vec<SocketAddr> {
    let mut listeners = Vec::with_capacity(count);
    let mut addrs = Vec::with_capacity(count);

    for _ in 0..count {
        let listener = TcpListener::bind("127.0.0.1:0").unwrap();
        let addr = listener.local_addr().unwrap();
        listeners.push(listener);
        addrs.push(addr);
    }
    addrs
}

/// Attempts to get the path of a Kudu executable (`kudu-master` or `kudu-tserver`). If the
/// `KUDU_HOME` environment variable is set, then that will be used, otherwise it will be searched
/// for on the path. If the executable can not be found, panic.
fn get_executable_path(executable: &str) -> PathBuf {
    if let Ok(kudu_home) = env::var("KUDU_HOME") {
        let mut bin = PathBuf::from(&kudu_home);
        bin.push("build");
        bin.push("latest");
        bin.push("bin");
        bin.push(executable);
        return bin;
    }

    let path_bytes = Command::new("which")
                             .arg(executable)
                             .output()
                             .unwrap()
                             .stdout;
    let path = CString::new(path_bytes).unwrap().into_string().unwrap();

    PathBuf::from(path.lines().next().expect(
            &format!("unable to find the {} executable. Set $KUDU_HOME or add it to $PATH",
                     executable)))
}

/// Mini cluster configuration options. Unless otherwise specified, the defaults match the master
/// and tablet server defaults.
pub struct MiniClusterConfig {
    /// The number of masters in the mini cluster. Default: 1.
    num_masters: i32,
    /// The number of tablet servers in the mini cluster. Default: 1.
    num_tservers: i32,

    // Logging Options

    /// Minimum logging level.
    min_log_level: Option<LogLevel>,

    /// Show all `VLOG(m)` messages for `m < this`. Overridden by `vmodule`.
    vlog: Option<i32>,

    /// Per-module `VLOG` level. List of (<module name>, <log level>) pairs. <module name> is a
    /// glob pattern, matched against the filename base (that is, name ignoring
    /// `.cc`/`.h`/`-inl.h`). <log level> overrides any value given by `vlog`.
    vmodule: Vec<(String, i32)>,

    /// If enabled, dump traces of all RPC negotiations to the log at `INFO` level.
    log_rpc_negotiation_trace: Option<bool>,

    /// If enabled, dump traces of all RPCs to the log at `INFO` level.
    log_rpc_trace: Option<bool>,

    // Latency Injection

    /// Amount of latency in milliseconds to inject into the RPC negotiation process.
    rpc_negotiation_delay: Option<i32>,

    /// Amount of latency in milliseconds to inject in GetTableLocations RPCs.
    get_table_locations_delay: Option<i32>,

    // Miscellaneous

    /// Whether to enable failure detection of tablet leaders. If enabled, attempts will be made to
    /// elect a follower as a new leader when the leader is detected to have failed.
    leader_failure_detection: Option<bool>,

    /// Whether to enable fsync() of data blocks, metadata, and their parent directories. Disabling
    /// this flag may cause data loss in the event of a system crash. Default: false.
    data_block_fsync: bool,
}

impl MiniClusterConfig {

    pub fn num_masters(&mut self, num_masters: i32) -> &mut MiniClusterConfig {
        self.num_masters = num_masters;
        self
    }

    pub fn num_tservers(&mut self, num_tservers: i32) -> &mut MiniClusterConfig {
        self.num_tservers = num_tservers;
        self
    }

    pub fn min_log_level(&mut self, log_level: LogLevel) -> &mut MiniClusterConfig {
        self.min_log_level = Some(log_level);
        self
    }

    pub fn vlog(&mut self, vlog_level: i32) -> &mut MiniClusterConfig {
        assert!(vlog_level >= 0);
        self.vlog = Some(vlog_level);
        self
    }

    pub fn vmodule(&mut self, module: String, vlog_level: i32) -> &mut MiniClusterConfig {
        assert!(vlog_level >= 0);
        self.vmodule.push((module, vlog_level));
        self
    }

    pub fn log_rpc_negotiation_trace(&mut self, log_rpc_negotiation_trace: bool) -> &mut MiniClusterConfig {
        self.log_rpc_negotiation_trace = Some(log_rpc_negotiation_trace);
        self
    }

    pub fn log_rpc_trace(&mut self, log_rpc_trace: bool) -> &mut MiniClusterConfig {
        self.log_rpc_trace = Some(log_rpc_trace);
        self
    }

    pub fn rpc_negotiation_delay(&mut self, millis: i32) -> &mut MiniClusterConfig {
        self.rpc_negotiation_delay = Some(millis);
        self
    }

    pub fn get_table_locations_delay(&mut self, millis: i32) -> &mut MiniClusterConfig {
        self.get_table_locations_delay = Some(millis);
        self
    }

    pub fn leader_failure_detection(&mut self, leader_failure_detection: bool) -> &mut MiniClusterConfig {
        self.leader_failure_detection = Some(leader_failure_detection);
        self
    }

    pub fn data_block_fsync(&mut self, data_block_fsync: bool) -> &mut MiniClusterConfig {
        self.data_block_fsync = data_block_fsync;
        self
    }

    fn args(&self) -> Vec<(&'static str, String)> {
        let mut args = Vec::new();

        if let Some(log_level) = self.min_log_level {
            args.push(("minloglevel", (log_level as usize).to_string()));
        }

        if let Some(vlog_level) = self.vlog {
            args.push(("v", vlog_level.to_string()));
        }

        if !self.vmodule.is_empty() {
            let modules = self.vmodule
                              .iter()
                              .map(|&(ref module, ref level)| format!("{}={}", module, level))
                              .collect::<Vec<_>>();
            args.push(("vmodule", modules.join(",")));
        }

        if let Some(log_rpc_negotiation_trace) = self.log_rpc_negotiation_trace {
            args.push(("rpc_trace_negotiation", log_rpc_negotiation_trace.to_string()));
        }

        if let Some(log_rpc_trace) = self.log_rpc_trace {
            args.push(("rpc_dump_all_traces", log_rpc_trace.to_string()));
        }

        if let Some(rpc_negotiation_delay) = self.rpc_negotiation_delay {
            args.push(("rpc_negotiation_inject_delay_ms", rpc_negotiation_delay.to_string()));
        }

        if let Some(get_table_locations_delay) = self.get_table_locations_delay {
            args.push(("master_inject_latency_on_tablet_lookup_ms",
                       get_table_locations_delay.to_string()));
        }

        if let Some(leader_failure_detection) = self.leader_failure_detection {
            args.push(("enable_leader_failure_detection",
                       leader_failure_detection.to_string()));
        }

        args.push(("enable_data_block_fsync",
                   self.data_block_fsync.to_string()));

        args
    }
}

impl Default for MiniClusterConfig {
    fn default() -> MiniClusterConfig {
        MiniClusterConfig {
            num_masters: 1,
            num_tservers: 1,
            min_log_level: None,
            vlog: None,
            vmodule: Vec::new(),
            log_rpc_negotiation_trace: None,
            log_rpc_trace: None,
            rpc_negotiation_delay: None,
            get_table_locations_delay: None,
            leader_failure_detection: None,
            data_block_fsync: false,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum LogLevel {
    Info = 0,
    Warning = 1,
    Error = 2,
    Fatal = 3,
}

#[cfg(test)]
mod tests {

    use env_logger;

    use super::*;

    #[test]
    fn test_spawn_mini_cluster() {
        let _ = env_logger::init();
        let _cluster = MiniCluster::default();
    }
}
<|endoftext|>


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

use std::str;

use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, LoaderTask, start_sending};

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use url::{percent_decode, OtherSchemeData};

pub fn factory() -> LoaderTask {
    proc(url, start_chan) {
        // NB: we don't spawn a new task.
        // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
        // Should be tested at some point.
        load(url, start_chan)
    }
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let url = load_data.url;
    assert!("data" == url.scheme.as_slice());

    let mut metadata = Metadata::default(url.clone());

    // Split out content type and data.
    let mut scheme_data = match url.scheme_data {
        OtherSchemeData(scheme_data) => scheme_data,
        _ => fail!("Expected a non-relative scheme URL.")
    };
    match url.query {
        Some(query) => {
            scheme_data.push_str("?");
            scheme_data.push_str(query.as_slice());
        },
        None => ()
    }
    let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
    if parts.len() != 2 {
        start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
        return;
    }

    // ";base64" must come at the end of the content type, per RFC 2397.
    // rust-http will fail to parse it because there's no =value part.
    let mut is_base64 = false;
    let mut ct_str = *parts.get(0);
    if ct_str.ends_with(";base64") {
        is_base64 = true;
        ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
    }

    // Parse the content type using rust-http.
    // FIXME: this can go into an infinite loop! (rust-http #25)
    let content_type: Option<MediaType> = from_stream_with_str(ct_str);
    metadata.set_content_type(&content_type);

    let progress_chan = start_sending(start_chan, metadata);
    let bytes = percent_decode(parts.get(1).as_bytes());

    if is_base64 {
        // FIXME(#2877): use bytes.as_slice().from_base64() when we upgrade to a Rust version
        // that includes https://github.com/rust-lang/rust/pull/15810
        let fake_utf8 = unsafe { str::raw::from_utf8(bytes.as_slice()) };
        match fake_utf8.from_base64() {
            Err(..) => {
                progress_chan.send(Done(Err("non-base64 data uri".to_string())));
            }
            Ok(data) => {
                progress_chan.send(Payload(data));
                progress_chan.send(Done(Ok(())));
            }
        }
    } else {
        progress_chan.send(Payload(bytes));
        progress_chan.send(Done(Ok(())));
    }
}

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<(String, String)>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use std::comm;
    use url::Url;

    let (start_chan, start_port) = comm::channel();
    load(LoadData::new(Url::parse(url).unwrap()), start_chan);

    let response = start_port.recv();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_string())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse("data:,hello%20world", None, None, Some(bytes!("hello world").iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse("data:text/plain,hello",
        Some(("text".to_string(), "plain".to_string())), None, Some(bytes!("hello").iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(bytes!("hello").iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<commit_msg>Ignore spaces in base64 data URLs. Fix #1268.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str;

use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, LoaderTask, start_sending};

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use url::{percent_decode, OtherSchemeData};

pub fn factory() -> LoaderTask {
    proc(url, start_chan) {
        // NB: we don't spawn a new task.
        // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
        // Should be tested at some point.
        load(url, start_chan)
    }
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let url = load_data.url;
    assert!("data" == url.scheme.as_slice());

    let mut metadata = Metadata::default(url.clone());

    // Split out content type and data.
    let mut scheme_data = match url.scheme_data {
        OtherSchemeData(scheme_data) => scheme_data,
        _ => fail!("Expected a non-relative scheme URL.")
    };
    match url.query {
        Some(query) => {
            scheme_data.push_str("?");
            scheme_data.push_str(query.as_slice());
        },
        None => ()
    }
    let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
    if parts.len() != 2 {
        start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
        return;
    }

    // ";base64" must come at the end of the content type, per RFC 2397.
    // rust-http will fail to parse it because there's no =value part.
    let mut is_base64 = false;
    let mut ct_str = *parts.get(0);
    if ct_str.ends_with(";base64") {
        is_base64 = true;
        ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
    }

    // Parse the content type using rust-http.
    // FIXME: this can go into an infinite loop! (rust-http #25)
    let content_type: Option<MediaType> = from_stream_with_str(ct_str);
    metadata.set_content_type(&content_type);

    let progress_chan = start_sending(start_chan, metadata);
    let bytes = percent_decode(parts.get(1).as_bytes());

    if is_base64 {
        // See #1268
        let bytes = bytes.move_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
        // FIXME(#2877): use bytes.as_slice().from_base64() when we upgrade to a Rust version
        // that includes https://github.com/rust-lang/rust/pull/15810
        let fake_utf8 = unsafe { str::raw::from_utf8(bytes.as_slice()) };
        match fake_utf8.from_base64() {
            Err(..) => {
                progress_chan.send(Done(Err("non-base64 data uri".to_string())));
            }
            Ok(data) => {
                progress_chan.send(Payload(data));
                progress_chan.send(Done(Ok(())));
            }
        }
    } else {
        progress_chan.send(Payload(bytes));
        progress_chan.send(Done(Ok(())));
    }
}

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<(String, String)>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use std::comm;
    use url::Url;

    let (start_chan, start_port) = comm::channel();
    load(LoadData::new(Url::parse(url).unwrap()), start_chan);

    let response = start_port.recv();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_string())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse("data:,hello%20world", None, None, Some(bytes!("hello world").iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse("data:text/plain,hello",
        Some(("text".to_string(), "plain".to_string())), None, Some(bytes!("hello").iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(bytes!("hello").iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<|endoftext|>