<commit_before>use actix::prelude::*;
use godcoin::prelude::*;

mod common;
pub use common::*;

#[test]
fn transfer_from_minter() {
    System::run(|| {
        let minter = TestMinter::new();
        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();

        let create_tx = |fee: &str, amount: Asset| {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, fee),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount,
                memo: vec![],
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };

        let from_bal = minter.chain().get_balance(&from_addr, &[]).unwrap();
        let amount = get_asset("1.0000 GRAEL");
        let tx = create_tx("1.0000 GRAEL", amount);
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(res, MsgResponse::Broadcast());
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(amount));

                // The fee transfers back to the minter wallet in the form of a reward tx so it
                // must not be subtracted during the assertion
                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, from_bal.sub(amount));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn transfer_from_user() {
    System::run(|| {
        let minter = TestMinter::new();

        let user_1_addr = KeyPair::gen();
        let user_2_addr = KeyPair::gen();

        let fut = {
            let tx = {
                let mut tx = TransferTx {
                    base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                    from: ScriptHash::from(&minter.genesis_info().script),
                    to: (&user_1_addr.0).into(),
                    amount: get_asset("100.0000 GRAEL"),
                    memo: vec![],
                    script: minter.genesis_info().script.clone(),
                };
                tx.append_sign(&minter.genesis_info().wallet_keys[3]);
                tx.append_sign(&minter.genesis_info().wallet_keys[0]);
                TxVariant::TransferTx(tx)
            };
            minter.request(MsgRequest::Broadcast(tx))
        };

        System::current().arbiter().send(
            fut.and_then({
                let user_1_addr = user_1_addr.clone();
                let user_2_addr = user_2_addr.clone();
                move |res| {
                    assert_eq!(res, MsgResponse::Broadcast());
                    let tx = {
                        let mut tx = TransferTx {
                            base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                            from: (&user_1_addr.0).into(),
                            to: (&user_2_addr.0).into(),
                            amount: get_asset("99.0000 GRAEL"),
                            memo: vec![],
                            script: user_1_addr.0.clone().into(),
                        };
                        tx.append_sign(&user_1_addr);
                        TxVariant::TransferTx(tx)
                    };
                    minter
                        .request(MsgRequest::Broadcast(tx))
                        .map(|res| (res, minter))
                }
            })
            .and_then(|(res, minter)| {
                assert_eq!(res, MsgResponse::Broadcast());
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let user_1_bal = minter.chain().get_balance(&user_1_addr.0.into(), &[]);
                assert_eq!(user_1_bal, Some(get_asset("0.0000 GRAEL")));

                let user_2_bal = minter.chain().get_balance(&user_2_addr.0.into(), &[]);
                assert_eq!(user_2_bal, Some(get_asset("99.0000 GRAEL")));

                let minter_addr = ScriptHash::from(&minter.genesis_info().script);
                let minter_bal = minter.chain().get_balance(&minter_addr, &[]);
                // The fee loops back to the minter in a reward transaction generated by the
                // minter block production
                assert_eq!(minter_bal, Some(get_asset("901.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn insufficient_balance_caused_by_fee() {
    System::run(|| {
        let minter = TestMinter::new();

        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();
        let tx = {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, "1001.0000 GRAEL"),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount: get_asset("0.0000 GRAEL"),
                memo: vec![],
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(
                    res,
                    MsgResponse::Error(net::ErrorKind::TxValidation(
                        verify::TxErr::InsufficientBalance
                    ))
                );
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(get_asset("0.0000 GRAEL")));

                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, Some(get_asset("1000.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn insufficient_balance_caused_by_amt() {
    System::run(|| {
        let minter = TestMinter::new();

        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();
        let tx = {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount: get_asset("500000.0000 GRAEL"),
                memo: vec![],
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(
                    res,
                    MsgResponse::Error(net::ErrorKind::TxValidation(
                        verify::TxErr::InsufficientBalance
                    ))
                );
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(get_asset("0.0000 GRAEL")));

                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, Some(get_asset("1000.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}
<commit_msg>Test transfer tx with a too large memo<commit_after>use actix::prelude::*;
use godcoin::prelude::*;

mod common;
pub use common::*;

#[test]
fn transfer_from_minter() {
    System::run(|| {
        let minter = TestMinter::new();
        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();

        let create_tx = |fee: &str, amount: Asset| {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, fee),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount,
                memo: vec![],
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };

        let from_bal = minter.chain().get_balance(&from_addr, &[]).unwrap();
        let amount = get_asset("1.0000 GRAEL");
        let tx = create_tx("1.0000 GRAEL", amount);
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(res, MsgResponse::Broadcast());
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(amount));

                // The fee transfers back to the minter wallet in the form of a reward tx so it
                // must not be subtracted during the assertion
                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, from_bal.sub(amount));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn transfer_from_user() {
    System::run(|| {
        let minter = TestMinter::new();

        let user_1_addr = KeyPair::gen();
        let user_2_addr = KeyPair::gen();

        let fut = {
            let tx = {
                let mut tx = TransferTx {
                    base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                    from: ScriptHash::from(&minter.genesis_info().script),
                    to: (&user_1_addr.0).into(),
                    amount: get_asset("100.0000 GRAEL"),
                    memo: vec![],
                    script: minter.genesis_info().script.clone(),
                };
                tx.append_sign(&minter.genesis_info().wallet_keys[3]);
                tx.append_sign(&minter.genesis_info().wallet_keys[0]);
                TxVariant::TransferTx(tx)
            };
            minter.request(MsgRequest::Broadcast(tx))
        };

        System::current().arbiter().send(
            fut.and_then({
                let user_1_addr = user_1_addr.clone();
                let user_2_addr = user_2_addr.clone();
                move |res| {
                    assert_eq!(res, MsgResponse::Broadcast());
                    let tx = {
                        let mut tx = TransferTx {
                            base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                            from: (&user_1_addr.0).into(),
                            to: (&user_2_addr.0).into(),
                            amount: get_asset("99.0000 GRAEL"),
                            memo: vec![],
                            script: user_1_addr.0.clone().into(),
                        };
                        tx.append_sign(&user_1_addr);
                        TxVariant::TransferTx(tx)
                    };
                    minter
                        .request(MsgRequest::Broadcast(tx))
                        .map(|res| (res, minter))
                }
            })
            .and_then(|(res, minter)| {
                assert_eq!(res, MsgResponse::Broadcast());
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let user_1_bal = minter.chain().get_balance(&user_1_addr.0.into(), &[]);
                assert_eq!(user_1_bal, Some(get_asset("0.0000 GRAEL")));

                let user_2_bal = minter.chain().get_balance(&user_2_addr.0.into(), &[]);
                assert_eq!(user_2_bal, Some(get_asset("99.0000 GRAEL")));

                let minter_addr = ScriptHash::from(&minter.genesis_info().script);
                let minter_bal = minter.chain().get_balance(&minter_addr, &[]);
                // The fee loops back to the minter in a reward transaction generated by the
                // minter block production
                assert_eq!(minter_bal, Some(get_asset("901.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn insufficient_balance_caused_by_fee() {
    System::run(|| {
        let minter = TestMinter::new();

        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();
        let tx = {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, "1001.0000 GRAEL"),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount: get_asset("0.0000 GRAEL"),
                memo: vec![],
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(
                    res,
                    MsgResponse::Error(net::ErrorKind::TxValidation(
                        verify::TxErr::InsufficientBalance
                    ))
                );
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(get_asset("0.0000 GRAEL")));

                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, Some(get_asset("1000.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn insufficient_balance_caused_by_amt() {
    System::run(|| {
        let minter = TestMinter::new();

        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();
        let tx = {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount: get_asset("500000.0000 GRAEL"),
                memo: vec![],
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(
                    res,
                    MsgResponse::Error(net::ErrorKind::TxValidation(
                        verify::TxErr::InsufficientBalance
                    ))
                );
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(get_asset("0.0000 GRAEL")));

                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, Some(get_asset("1000.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}

#[test]
fn memo_too_large() {
    System::run(|| {
        let minter = TestMinter::new();

        let from_addr = ScriptHash::from(&minter.genesis_info().script);
        let to_addr = KeyPair::gen();
        let tx = {
            let mut tx = TransferTx {
                base: create_tx_header(TxType::TRANSFER, "1.0000 GRAEL"),
                from: from_addr.clone(),
                to: (&to_addr.0).into(),
                amount: get_asset("1.0000 GRAEL"),
                memo: (0..=godcoin::constants::MAX_MEMO_BYTE_SIZE)
                    .map(|_| 0)
                    .collect(),
                script: minter.genesis_info().script.clone(),
            };
            tx.append_sign(&minter.genesis_info().wallet_keys[3]);
            tx.append_sign(&minter.genesis_info().wallet_keys[0]);
            TxVariant::TransferTx(tx)
        };
        let fut = minter.request(MsgRequest::Broadcast(tx));
        System::current().arbiter().send(
            fut.and_then(move |res| {
                assert_eq!(
                    res,
                    MsgResponse::Error(net::ErrorKind::TxValidation(verify::TxErr::TxTooLarge))
                );
                minter.produce_block().map(|_| minter)
            })
            .and_then(move |minter| {
                let chain = minter.chain();
                let cur_bal = chain.get_balance(&to_addr.0.into(), &[]);
                assert_eq!(cur_bal, Some(get_asset("0.0000 GRAEL")));

                let cur_bal = chain.get_balance(&from_addr, &[]);
                assert_eq!(cur_bal, Some(get_asset("1000.0000 GRAEL")));

                System::current().stop();
                Ok(())
            }),
        );
    })
    .unwrap();
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::io;

#[derive(Debug)]
pub struct InvalidValueError;

#[derive(Debug)]
pub struct DataLengthError;

#[derive(Debug)]
pub enum TryFromError {
    InvalidValue,
}

#[derive(Debug)]
#[deprecated(note = "Use custom `io::Error`s instead")]
#[doc(hidden)]
pub enum ReadError {
    InvalidValue,
    UnexpectedEof,
    LimitReached,
    IoError(io::Error),
}

#[derive(Debug)]
#[deprecated(note = "Use custom `io::Error`s instead")]
pub enum WriteError {
    IoError(io::Error),
    DataLengthOverflow
}

impl_err_display!(InvalidValueError);

impl InvalidValueError {
    pub fn new() -> io::Error {
        io::Error::new(io::ErrorKind::InvalidData, InvalidValueError {})
    }
}

impl Error for InvalidValueError {
    fn description(&self) -> &str {
        "Invalid value"
    }
}

impl_err_display!(DataLengthError);

impl DataLengthError {
    pub fn new() -> io::Error {
        io::Error::new(io::ErrorKind::InvalidData, DataLengthError {})
    }
}

impl Error for DataLengthError {
    fn description(&self) -> &str {
        "Data length does not match or overflows maximum"
    }
}

impl_err_display!(TryFromError);

impl Error for TryFromError {
    fn description(&self) -> &str {
        "Invalid value"
    }
}

impl From<TryFromError> for io::Error {
    fn from(err: TryFromError) -> Self {
        io::Error::new(io::ErrorKind::InvalidData, err)
    }
}

impl From<TryFromError> for ReadError {
    fn from(_: TryFromError) -> Self {
        ReadError::InvalidValue
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> Self {
        ReadError::IoError(err)
    }
}

impl_err_display!(ReadError);

impl Error for ReadError {
    fn description(&self) -> &str {
        match self {
            &ReadError::InvalidValue => "invalid value",
            &ReadError::UnexpectedEof => "unexpected eof",
            &ReadError::LimitReached => "limit reached",
            &ReadError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ReadError::IoError(ref err) => err.cause(),
            _ => None,
        }
    }
}

impl_err_display!(WriteError);

impl Error for WriteError {
    fn description(&self) -> &str {
        match self {
            &WriteError::IoError(ref err) => err.description(),
            &WriteError::DataLengthOverflow => "Data overflows maximum length",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &WriteError::IoError(ref err) => err.cause(),
            _ => None,
        }
    }
}

impl From<io::Error> for WriteError {
    fn from(err: io::Error) -> Self {
        WriteError::IoError(err)
    }
}<commit_msg>Add convert trait WriteError -> io::Error<commit_after>use std::error::Error;
use std::io;

#[derive(Debug)]
pub struct InvalidValueError;

#[derive(Debug)]
pub struct DataLengthError;

#[derive(Debug)]
pub enum TryFromError {
    InvalidValue,
}

#[derive(Debug)]
#[deprecated(note = "Use custom `io::Error`s instead")]
#[doc(hidden)]
pub enum ReadError {
    InvalidValue,
    UnexpectedEof,
    LimitReached,
    IoError(io::Error),
}

#[derive(Debug)]
#[deprecated(note = "Use custom `io::Error`s instead")]
pub enum WriteError {
    IoError(io::Error),
    DataLengthOverflow
}

impl_err_display!(InvalidValueError);

impl InvalidValueError {
    pub fn new() -> io::Error {
        io::Error::new(io::ErrorKind::InvalidData, InvalidValueError {})
    }
}

impl Error for InvalidValueError {
    fn description(&self) -> &str {
        "Invalid value"
    }
}

impl_err_display!(DataLengthError);

impl DataLengthError {
    pub fn new() -> io::Error {
        io::Error::new(io::ErrorKind::InvalidData, DataLengthError {})
    }
}

impl Error for DataLengthError {
    fn description(&self) -> &str {
        "Data length does not match or overflows maximum"
    }
}

impl_err_display!(TryFromError);

impl Error for TryFromError {
    fn description(&self) -> &str {
        "Invalid value"
    }
}

impl From<TryFromError> for io::Error {
    fn from(err: TryFromError) -> Self {
        io::Error::new(io::ErrorKind::InvalidData, err)
    }
}

impl From<TryFromError> for ReadError {
    fn from(_: TryFromError) -> Self {
        ReadError::InvalidValue
    }
}

impl From<io::Error> for ReadError {
    fn from(err: io::Error) -> Self {
        ReadError::IoError(err)
    }
}

impl_err_display!(ReadError);

impl Error for ReadError {
    fn description(&self) -> &str {
        match self {
            &ReadError::InvalidValue => "invalid value",
            &ReadError::UnexpectedEof => "unexpected eof",
            &ReadError::LimitReached => "limit reached",
            &ReadError::IoError(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &ReadError::IoError(ref err) => err.cause(),
            _ => None,
        }
    }
}

impl_err_display!(WriteError);

impl Error for WriteError {
    fn description(&self) -> &str {
        match self {
            &WriteError::IoError(ref err) => err.description(),
            &WriteError::DataLengthOverflow => "Data overflows maximum length",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &WriteError::IoError(ref err) => err.cause(),
            _ => None,
        }
    }
}

impl From<io::Error> for WriteError {
    fn from(err: io::Error) -> Self {
        WriteError::IoError(err)
    }
}

impl From<WriteError> for io::Error {
    fn from(err: WriteError) -> Self {
        match err {
            WriteError::IoError(err) => err,
            WriteError::DataLengthOverflow => io::Error::new(io::ErrorKind::Other, WriteError::DataLengthOverflow),
        }
    }
}<|endoftext|>


<commit_before>
use std::sync::Arc;

use rocksdb::{DB, WriteBatch};
use proto::raft_serverpb::StoreIdent;
use proto::metapb;
use raftserver::{Result, other};
use super::keys;
use super::engine::{Retriever, Mutator};

// How to construct cluster?
//
// Use bootstrap_cluster to bootstrap cluster first, this function will create
// node 1 and store 1 for this cluster.
// When we start store, we must first check whether the store is bootstrapped or not
// using is_store_bootstrapped, if not, we must call bootstrap_store to bootstrap it first.

pub const BOOTSTRAP_FIRST_NODE_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_STORE_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_REGION_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_PEER_ID: u64 = 1;

pub fn is_store_bootstrapped(engine: Arc<DB>, cluster_id: u64) -> Result<bool> {
    let res = try!(engine.get_msg::<StoreIdent>(&keys::store_ident_key()));
    match res {
        None => Ok(false),
        Some(ident) => {
            if ident.get_cluster_id() != cluster_id {
                return Err(other(format!("store is bootstrapped for cluster {} already",
                                         ident.get_cluster_id())));
            }
            Ok(true)
        }
    }
}

// Bootstrap the store, the DB for this store must be empty and has no data.
pub fn bootstrap_store(engine: Arc<DB>,
                       cluster_id: u64,
                       node_id: u64,
                       store_id: u64)
                       -> Result<()> {
    let mut ident = StoreIdent::new();

    let mut count: u32 = 0;
    try!(engine.scan(keys::MIN_KEY,
                     keys::MAX_KEY,
                     &mut |_, _| -> Result<(bool)> {
                         count += 1;
                         Ok(false)
                     }));

    if count > 0 {
        return Err(other("store is not empty and has already had data."));
    }

    let ident_key = keys::store_ident_key();
    try!(engine.get_msg::<StoreIdent>(&ident_key).and_then(|res| {
        if res.is_some() {
            let res = res.unwrap();
            return Err(other(format!("store has already been bootstrapped to cluster {}",
                                     res.get_cluster_id())));
        }

        Ok(())
    }));

    ident.set_cluster_id(cluster_id);
    ident.set_node_id(node_id);
    ident.set_store_id(store_id);

    engine.put_msg(&ident_key, &ident)
}

// Bootstrap first region, the region id must be 1 and start/end key is
// min_key/max_key. The first peer id is 1 too.
fn bootstrap_region(engine: Arc<DB>) -> Result<()> {
    let mut region = metapb::Region::new();
    region.set_region_id(BOOTSTRAP_FIRST_NODE_ID);
    region.set_start_key(keys::MIN_KEY.to_vec());
    region.set_end_key(keys::MAX_KEY.to_vec());

    let mut peer = metapb::Peer::new();
    peer.set_node_id(BOOTSTRAP_FIRST_NODE_ID);
    peer.set_store_id(BOOTSTRAP_FIRST_STORE_ID);
    peer.set_peer_id(BOOTSTRAP_FIRST_PEER_ID);

    let batch = WriteBatch::new();
    try!(batch.put_msg(&keys::region_info_key(region.get_start_key()), &region));

    // meta2 key for this region is \x03\0xff
    let meta2_key = keys::region_route_meta_key(keys::MAX_KEY);
    try!(batch.put_msg(&meta2_key, &region));

    // meta1 key for meta2 is \0x02\0xff
    let meta1_key = keys::region_route_meta_key(&meta2_key);
    try!(batch.put_msg(&meta1_key, &region));

    try!(engine.write(batch));

    Ok(())
}

// Bootstrap cluster, we must bootstrap the first store with node/store id both are 1,
// and first region.
pub fn bootstrap_cluster(engine: Arc<DB>, cluster_id: u64) -> Result<()> {
    try!(bootstrap_store(engine.clone(),
                         cluster_id,
                         BOOTSTRAP_FIRST_NODE_ID,
                         BOOTSTRAP_FIRST_STORE_ID));
    try!(bootstrap_region(engine.clone()));
    Ok(())
}
<commit_msg>raftserver: Address comment.<commit_after>
use std::sync::Arc;

use rocksdb::{DB, WriteBatch};
use proto::raft_serverpb::StoreIdent;
use proto::metapb;
use raftserver::{Result, other};
use super::keys;
use super::engine::{Retriever, Mutator};

// How to construct cluster?
//
// Use bootstrap_cluster to bootstrap cluster first, this function will create
// node 1 and store 1 for this cluster.
// When we start store, we must first check whether the store is bootstrapped or not
// using is_store_bootstrapped, if not, we must call bootstrap_store to bootstrap it first.

pub const BOOTSTRAP_FIRST_NODE_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_STORE_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_REGION_ID: u64 = 1;
pub const BOOTSTRAP_FIRST_PEER_ID: u64 = 1;

pub fn is_store_bootstrapped(engine: Arc<DB>, cluster_id: u64) -> Result<bool> {
    let res = try!(engine.get_msg::<StoreIdent>(&keys::store_ident_key()));
    match res {
        None => Ok(false),
        Some(ident) => {
            if ident.get_cluster_id() != cluster_id {
                return Err(other(format!("store is bootstrapped for cluster {} already",
                                         ident.get_cluster_id())));
            }
            Ok(true)
        }
    }
}

// Bootstrap the store, the DB for this store must be empty and has no data.
pub fn bootstrap_store(engine: Arc<DB>,
                       cluster_id: u64,
                       node_id: u64,
                       store_id: u64)
                       -> Result<()> {
    let mut ident = StoreIdent::new();

    let mut count: u32 = 0;
    try!(engine.scan(keys::MIN_KEY,
                     keys::MAX_KEY,
                     &mut |_, _| -> Result<(bool)> {
                         count += 1;
                         Ok(false)
                     }));

    if count > 0 {
        return Err(other("store is not empty and has already had data."));
    }

    let ident_key = keys::store_ident_key();
    try!(engine.get_msg::<StoreIdent>(&ident_key).and_then(|res| {
        if let Some(res) = res {
            return Err(other(format!("store has already been bootstrapped to cluster {}",
                                     res.get_cluster_id())));
        }

        Ok(())
    }));

    ident.set_cluster_id(cluster_id);
    ident.set_node_id(node_id);
    ident.set_store_id(store_id);

    engine.put_msg(&ident_key, &ident)
}

// Bootstrap first region, the region id must be 1 and start/end key is
// min_key/max_key. The first peer id is 1 too.
fn bootstrap_region(engine: Arc<DB>) -> Result<()> {
    let mut region = metapb::Region::new();
    region.set_region_id(BOOTSTRAP_FIRST_NODE_ID);
    region.set_start_key(keys::MIN_KEY.to_vec());
    region.set_end_key(keys::MAX_KEY.to_vec());

    let mut peer = metapb::Peer::new();
    peer.set_node_id(BOOTSTRAP_FIRST_NODE_ID);
    peer.set_store_id(BOOTSTRAP_FIRST_STORE_ID);
    peer.set_peer_id(BOOTSTRAP_FIRST_PEER_ID);

    let batch = WriteBatch::new();
    try!(batch.put_msg(&keys::region_info_key(region.get_start_key()), &region));

    // meta2 key for this region is \x03\0xff
    let meta2_key = keys::region_route_meta_key(keys::MAX_KEY);
    try!(batch.put_msg(&meta2_key, &region));

    // meta1 key for meta2 is \0x02\0xff
    let meta1_key = keys::region_route_meta_key(&meta2_key);
    try!(batch.put_msg(&meta1_key, &region));

    try!(engine.write(batch));

    Ok(())
}

// Bootstrap cluster, we must bootstrap the first store with node/store id both are 1,
// and first region.
pub fn bootstrap_cluster(engine: Arc<DB>, cluster_id: u64) -> Result<()> {
    try!(bootstrap_store(engine.clone(),
                         cluster_id,
                         BOOTSTRAP_FIRST_NODE_ID,
                         BOOTSTRAP_FIRST_STORE_ID));
    try!(bootstrap_region(engine.clone()));
    Ok(())
}
<|endoftext|>


<commit_before>mod math;
mod modification;

pub use self::{
    math::{EuclDiv, OpError, Pow},
    modification::Modifications,
};
use super::{colors::Colors, flow_control::Function};
use crate::{
    sys::{env as sys_env, geteuid, getpid, getuid, variables as self_sys},
    types::{self, Array},
};
use itertools::Itertools;
use scopes::{Namespace, Scope, Scopes};
use std::{env, fmt};
use unicode_segmentation::UnicodeSegmentation;
use xdg::BaseDirectories;

#[derive(Clone, Debug, PartialEq)]
pub enum Value<'a> {
    Str(types::Str),
    Alias(types::Alias),
    Array(types::Array<'a>),
    HashMap(types::HashMap<'a>),
    BTreeMap(types::BTreeMap<'a>),
    Function(Function<'a>),
    None,
}

macro_rules! type_from_value {
    ($to:ty : $variant:ident else $defaultmethod:ident($($args:expr),*)) => {
        impl<'a> From<Value<'a>> for $to {
            fn from(var: Value<'a>) -> Self {
                match var {
                    Value::$variant(inner) => inner,
                    _ => <$to>::$defaultmethod($($args),*),
                }
            }
        }

        impl<'a> From<Value<'a>> for Option<$to> {
            fn from(var: Value<'a>) -> Self {
                match var {
                    Value::$variant(inner) => Some(inner),
                    _ => None,
                }
            }
        }

        impl<'a, 'b> From<&'b Value<'a>> for Option<&'b $to> {
            fn from(var: &'b Value<'a>) -> Self {
                match *var {
                    Value::$variant(ref inner) => Some(inner),
                    _ => None,
                }
            }
        }

        impl<'a, 'b> From<&'b mut Value<'a>> for Option<&'b mut $to> {
            fn from(var: &'b mut Value<'a>) -> Self {
                match *var {
                    Value::$variant(ref mut inner) => Some(inner),
                    _ => None,
                }
            }
        }
    }
}

type_from_value!(types::Str : Str else with_capacity(0));
type_from_value!(types::Alias : Alias else empty());
type_from_value!(types::Array<'a> : Array else with_capacity(0));
type_from_value!(types::HashMap<'a> : HashMap else with_capacity_and_hasher(0, Default::default()));
type_from_value!(types::BTreeMap<'a> : BTreeMap else new());
type_from_value!(Function<'a> : Function else
    new(
        Default::default(),
        Default::default(),
        Default::default(),
        Default::default()
    )
);

impl<'a> Eq for Value<'a> {}

// this one’s only special because of the lifetime parameter
impl<'a, 'b> From<&'b str> for Value<'a> {
    fn from(string: &'b str) -> Self { Value::Str(string.into()) }
}

macro_rules! value_from_type {
    ($arg:ident: $from:ty => $variant:ident($inner:expr)) => {
        impl<'a> From<$from> for Value<'a> {
            fn from($arg: $from) -> Self { Value::$variant($inner) }
        }
    };
}

value_from_type!(string: types::Str => Str(string));
value_from_type!(string: String => Str(string.into()));
value_from_type!(alias: types::Alias => Alias(alias));
value_from_type!(array: types::Array<'a> => Array(array));
value_from_type!(hmap: types::HashMap<'a> => HashMap(hmap));
value_from_type!(bmap: types::BTreeMap<'a> => BTreeMap(bmap));
value_from_type!(function: Function<'a> => Function(function));

impl<'a> fmt::Display for Value<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Value::Str(ref str_) => write!(f, "{}", str_),
            Value::Alias(ref alias) => write!(f, "{}", **alias),
            Value::Array(ref array) => write!(f, "{}", array.iter().format(" ")),
            Value::HashMap(ref map) => write!(f, "{}", map.values().format(" ")),
            Value::BTreeMap(ref map) => write!(f, "{}", map.values().format(" ")),
            _ => write!(f, ""),
        }
    }
}

pub struct Variables<'a>(Scopes<types::Str, Value<'a>>);

impl<'a> Variables<'a> {
    pub fn string_vars(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().flat_map(|map| {
            map.iter().filter_map(
                |(key, val)| {
                    if let Value::Str(val) = val {
                        Some((key, val))
                    } else {
                        None
                    }
                },
            )
        })
    }

    pub fn aliases(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, possible_alias)| {
                if let Value::Alias(alias) = possible_alias {
                    Some((key, &**alias))
                } else {
                    None
                }
            })
        })
    }

    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Function<'a>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let Value::Function(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array<'a>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(
                |(key, val)| {
                    if let Value::Array(val) = val {
                        Some((key, val))
                    } else {
                        None
                    }
                },
            )
        })
    }

    pub fn new_scope(&mut self, namespace: bool) { self.0.new_scope(namespace) }

    pub fn pop_scope(&mut self) { self.0.pop_scope() }

    pub fn pop_scopes<'b>(
        &'b mut self,
        index: usize,
    ) -> impl Iterator<Item = Scope<types::Str, Value<'a>>> + 'b {
        self.0.pop_scopes(index)
    }

    pub fn append_scopes(&mut self, scopes: Vec<Scope<types::Str, Value<'a>>>) {
        self.0.append_scopes(scopes)
    }

    pub fn index_scope_for_var(&self, name: &str) -> Option<usize> {
        self.0.index_scope_for_var(name)
    }

    pub fn set<T: Into<Value<'a>>>(&mut self, name: &str, value: T) {
        let value = value.into();
        if let Some(val) = self.0.get_mut(name) {
            std::mem::replace(val, value);
        } else {
            self.0.set(name, value);
        }
    }

    /// Obtains the value for the **MWD** variable.
    ///
    /// Further minimizes the directory path in the same manner that Fish does by default.
    /// That is, if more than two parents are visible in the path, all parent directories
    /// of the current directory will be reduced to a single character.
    fn get_minimal_directory(&self) -> types::Str {
        let swd = self.get_simplified_directory();

        {
            // Temporarily borrow the `swd` variable while we attempt to assemble a minimal
            // variant of the directory path. If that is not possible, we will cancel the
            // borrow and return `swd` itself as the minified path.
            let elements = swd.split('/').filter(|s| !s.is_empty()).collect::<Vec<&str>>();
            if elements.len() > 2 {
                let mut output = types::Str::new();
                for element in &elements[..elements.len() - 1] {
                    let mut segmenter = UnicodeSegmentation::graphemes(*element, true);
                    let grapheme = segmenter.next().unwrap();
                    output.push_str(grapheme);
                    if grapheme == "." {
                        output.push_str(segmenter.next().unwrap());
                    }
                    output.push('/');
                }
                output.push_str(&elements[elements.len() - 1]);
                return output;
            }
        }

        swd
    }

    /// Obtains the value for the **SWD** variable.
    ///
    /// Useful for getting smaller prompts, this will produce a simplified variant of the
    /// working directory which the leading `HOME` prefix replaced with a tilde character.
    fn get_simplified_directory(&self) -> types::Str {
        let home = self.get_str("HOME").unwrap_or_else(|| "?".into());
        env::var("PWD").unwrap().replace(&*home, "~").into()
    }

    pub fn is_valid_variable_name(name: &str) -> bool {
        name.chars().all(Variables::is_valid_variable_character)
    }

    pub fn is_valid_variable_character(c: char) -> bool {
        c.is_alphanumeric() || c == '_' || c == '?' || c == '.' || c == '-' || c == '+'
    }

    pub fn remove_variable(&mut self, name: &str) -> Option<Value<'a>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.remove_variable(name)
    }

    pub fn get_mut(&mut self, name: &str) -> Option<&mut Value<'a>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.get_mut(name)
    }

    pub fn get_str(&self, name: &str) -> Option<types::Str> {
        match name {
            "MWD" => return Some(self.get_minimal_directory()),
            "SWD" => return Some(self.get_simplified_directory()),
            _ => (),
        }
        // If the parsed name contains the '::' pattern, then a namespace was
        // designated. Find it.
        match name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
            Some(("c", variable)) | Some(("color", variable)) => {
                Colors::collect(variable).into_string().map(|s| s.into())
            }
            Some(("x", variable)) | Some(("hex", variable)) => {
                match u8::from_str_radix(variable, 16) {
                    Ok(c) => Some((c as char).to_string().into()),
                    Err(why) => {
                        eprintln!("ion: hex parse error: {}: {}", variable, why);
                        None
                    }
                }
            }
            Some(("env", variable)) => env::var(variable).map(Into::into).ok().map(|s| s),
            Some(("super", _)) | Some(("global", _)) | None => {
                // Otherwise, it's just a simple variable name.
                match self.get_ref(name) {
                    Some(Value::Str(val)) => Some(val.clone()),
                    _ => env::var(name).ok().map(|s| s.into()),
                }
            }
            Some((..)) => {
                eprintln!("ion: unsupported namespace: '{}'", name);
                None
            }
        }
    }

    pub fn get_ref(&self, mut name: &str) -> Option<&Value<'a>> {
        const GLOBAL_NS: &str = "global::";
        const SUPER_NS: &str = "super::";

        let namespace = if name.starts_with(GLOBAL_NS) {
            name = &name[GLOBAL_NS.len()..];
            // Go up as many namespaces as possible
            Namespace::Global
        } else if name.starts_with(SUPER_NS) {
            let mut up = 0;
            while name.starts_with(SUPER_NS) {
                name = &name[SUPER_NS.len()..];
                up += 1;
            }

            Namespace::Specific(up)
        } else {
            Namespace::Any
        };
        self.0.get_ref(name, namespace)
    }
}

impl<'a> Default for Variables<'a> {
    fn default() -> Self {
        let mut map: Scopes<types::Str, Value<'a>> = Scopes::with_capacity(64);
        map.set("DIRECTORY_STACK_SIZE", "1000");
        map.set("HISTORY_SIZE", "1000");
        map.set("HISTFILE_SIZE", "100000");
        map.set(
            "PROMPT",
            "${x::1B}]0;${USER}: \
             ${PWD}${x::07}${c::0x55,bold}${USER}${c::default}:${c::0x4B}${SWD}${c::default}# \
             ${c::reset}",
        );

        // Set the PID, UID, and EUID variables.
        map.set("PID", Value::Str(getpid().ok().map_or("?".into(), |id| id.to_string().into())));
        map.set("UID", Value::Str(getuid().ok().map_or("?".into(), |id| id.to_string().into())));
        map.set("EUID", Value::Str(geteuid().ok().map_or("?".into(), |id| id.to_string().into())));

        // Initialize the HISTFILE variable
        if let Ok(base_dirs) = BaseDirectories::with_prefix("ion") {
            if let Ok(path) = base_dirs.place_data_file("history") {
                map.set("HISTFILE", path.to_str().unwrap_or("?"));
                map.set("HISTFILE_ENABLED", "1");
            }
        }

        // History Timestamps enabled variable, disabled by default
        map.set("HISTORY_TIMESTAMP", "0");

        map.set("HISTORY_IGNORE", array!["no_such_command", "whitespace", "duplicates"]);

        map.set("CDPATH", Array::new());

        // Initialize the HOME variable
        sys_env::home_dir().map_or_else(
            || env::set_var("HOME", "?"),
            |path| env::set_var("HOME", path.to_str().unwrap_or("?")),
        );

        // Initialize the HOST variable
        env::set_var("HOST", &self_sys::get_host_name().unwrap_or_else(|| "?".to_owned()));

        Variables(map)
    }
}

#[cfg(test)]
mod trait_test;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parser::Expander;
    use serial_test_derive::serial;

    struct VariableExpander<'a>(pub Variables<'a>);

    impl<'a> Expander for VariableExpander<'a> {
        fn string(&self, var: &str) -> Option<types::Str> { self.0.get_str(var) }
    }

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::default();
        let expanded = VariableExpander(variables).expand_string("$FOO").join("");
        assert_eq!("", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set("FOO", "BAR");
        let expanded = VariableExpander(variables).expand_string("$FOO").join("");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    #[serial]
    fn minimal_directory_var_should_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log/nix");
        assert_eq!(
            types::Str::from("v/l/nix"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }

    #[test]
    #[serial]
    fn minimal_directory_var_shouldnt_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log");
        assert_eq!(
            types::Str::from("/var/log"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }
}
<commit_msg>Remove directory stack var<commit_after>mod math;
mod modification;

pub use self::{
    math::{EuclDiv, OpError, Pow},
    modification::Modifications,
};
use super::{colors::Colors, flow_control::Function};
use crate::{
    sys::{env as sys_env, geteuid, getpid, getuid, variables as self_sys},
    types::{self, Array},
};
use itertools::Itertools;
use scopes::{Namespace, Scope, Scopes};
use std::{env, fmt};
use unicode_segmentation::UnicodeSegmentation;
use xdg::BaseDirectories;

#[derive(Clone, Debug, PartialEq)]
pub enum Value<'a> {
    Str(types::Str),
    Alias(types::Alias),
    Array(types::Array<'a>),
    HashMap(types::HashMap<'a>),
    BTreeMap(types::BTreeMap<'a>),
    Function(Function<'a>),
    None,
}

macro_rules! type_from_value {
    ($to:ty : $variant:ident else $defaultmethod:ident($($args:expr),*)) => {
        impl<'a> From<Value<'a>> for $to {
            fn from(var: Value<'a>) -> Self {
                match var {
                    Value::$variant(inner) => inner,
                    _ => <$to>::$defaultmethod($($args),*),
                }
            }
        }

        impl<'a> From<Value<'a>> for Option<$to> {
            fn from(var: Value<'a>) -> Self {
                match var {
                    Value::$variant(inner) => Some(inner),
                    _ => None,
                }
            }
        }

        impl<'a, 'b> From<&'b Value<'a>> for Option<&'b $to> {
            fn from(var: &'b Value<'a>) -> Self {
                match *var {
                    Value::$variant(ref inner) => Some(inner),
                    _ => None,
                }
            }
        }

        impl<'a, 'b> From<&'b mut Value<'a>> for Option<&'b mut $to> {
            fn from(var: &'b mut Value<'a>) -> Self {
                match *var {
                    Value::$variant(ref mut inner) => Some(inner),
                    _ => None,
                }
            }
        }
    }
}

type_from_value!(types::Str : Str else with_capacity(0));
type_from_value!(types::Alias : Alias else empty());
type_from_value!(types::Array<'a> : Array else with_capacity(0));
type_from_value!(types::HashMap<'a> : HashMap else with_capacity_and_hasher(0, Default::default()));
type_from_value!(types::BTreeMap<'a> : BTreeMap else new());
type_from_value!(Function<'a> : Function else
    new(
        Default::default(),
        Default::default(),
        Default::default(),
        Default::default()
    )
);

impl<'a> Eq for Value<'a> {}

// this one’s only special because of the lifetime parameter
impl<'a, 'b> From<&'b str> for Value<'a> {
    fn from(string: &'b str) -> Self { Value::Str(string.into()) }
}

macro_rules! value_from_type {
    ($arg:ident: $from:ty => $variant:ident($inner:expr)) => {
        impl<'a> From<$from> for Value<'a> {
            fn from($arg: $from) -> Self { Value::$variant($inner) }
        }
    };
}

value_from_type!(string: types::Str => Str(string));
value_from_type!(string: String => Str(string.into()));
value_from_type!(alias: types::Alias => Alias(alias));
value_from_type!(array: types::Array<'a> => Array(array));
value_from_type!(hmap: types::HashMap<'a> => HashMap(hmap));
value_from_type!(bmap: types::BTreeMap<'a> => BTreeMap(bmap));
value_from_type!(function: Function<'a> => Function(function));

impl<'a> fmt::Display for Value<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Value::Str(ref str_) => write!(f, "{}", str_),
            Value::Alias(ref alias) => write!(f, "{}", **alias),
            Value::Array(ref array) => write!(f, "{}", array.iter().format(" ")),
            Value::HashMap(ref map) => write!(f, "{}", map.values().format(" ")),
            Value::BTreeMap(ref map) => write!(f, "{}", map.values().format(" ")),
            _ => write!(f, ""),
        }
    }
}

pub struct Variables<'a>(Scopes<types::Str, Value<'a>>);

impl<'a> Variables<'a> {
    pub fn string_vars(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().flat_map(|map| {
            map.iter().filter_map(
                |(key, val)| {
                    if let Value::Str(val) = val {
                        Some((key, val))
                    } else {
                        None
                    }
                },
            )
        })
    }

    pub fn aliases(&self) -> impl Iterator<Item = (&types::Str, &types::Str)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, possible_alias)| {
                if let Value::Alias(alias) = possible_alias {
                    Some((key, &**alias))
                } else {
                    None
                }
            })
        })
    }

    pub fn functions(&self) -> impl Iterator<Item = (&types::Str, &Function<'a>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(|(key, val)| {
                if let Value::Function(val) = val {
                    Some((key, val))
                } else {
                    None
                }
            })
        })
    }

    pub fn arrays(&self) -> impl Iterator<Item = (&types::Str, &types::Array<'a>)> {
        self.0.scopes().rev().flat_map(|map| {
            map.iter().filter_map(
                |(key, val)| {
                    if let Value::Array(val) = val {
                        Some((key, val))
                    } else {
                        None
                    }
                },
            )
        })
    }

    pub fn new_scope(&mut self, namespace: bool) { self.0.new_scope(namespace) }

    pub fn pop_scope(&mut self) { self.0.pop_scope() }

    pub fn pop_scopes<'b>(
        &'b mut self,
        index: usize,
    ) -> impl Iterator<Item = Scope<types::Str, Value<'a>>> + 'b {
        self.0.pop_scopes(index)
    }

    pub fn append_scopes(&mut self, scopes: Vec<Scope<types::Str, Value<'a>>>) {
        self.0.append_scopes(scopes)
    }

    pub fn index_scope_for_var(&self, name: &str) -> Option<usize> {
        self.0.index_scope_for_var(name)
    }

    pub fn set<T: Into<Value<'a>>>(&mut self, name: &str, value: T) {
        let value = value.into();
        if let Some(val) = self.0.get_mut(name) {
            std::mem::replace(val, value);
        } else {
            self.0.set(name, value);
        }
    }

    /// Obtains the value for the **MWD** variable.
    ///
    /// Further minimizes the directory path in the same manner that Fish does by default.
    /// That is, if more than two parents are visible in the path, all parent directories
    /// of the current directory will be reduced to a single character.
    fn get_minimal_directory(&self) -> types::Str {
        let swd = self.get_simplified_directory();

        {
            // Temporarily borrow the `swd` variable while we attempt to assemble a minimal
            // variant of the directory path. If that is not possible, we will cancel the
            // borrow and return `swd` itself as the minified path.
            let elements = swd.split('/').filter(|s| !s.is_empty()).collect::<Vec<&str>>();
            if elements.len() > 2 {
                let mut output = types::Str::new();
                for element in &elements[..elements.len() - 1] {
                    let mut segmenter = UnicodeSegmentation::graphemes(*element, true);
                    let grapheme = segmenter.next().unwrap();
                    output.push_str(grapheme);
                    if grapheme == "." {
                        output.push_str(segmenter.next().unwrap());
                    }
                    output.push('/');
                }
                output.push_str(&elements[elements.len() - 1]);
                return output;
            }
        }

        swd
    }

    /// Obtains the value for the **SWD** variable.
    ///
    /// Useful for getting smaller prompts, this will produce a simplified variant of the
    /// working directory which the leading `HOME` prefix replaced with a tilde character.
    fn get_simplified_directory(&self) -> types::Str {
        let home = self.get_str("HOME").unwrap_or_else(|| "?".into());
        env::var("PWD").unwrap().replace(&*home, "~").into()
    }

    pub fn is_valid_variable_name(name: &str) -> bool {
        name.chars().all(Variables::is_valid_variable_character)
    }

    pub fn is_valid_variable_character(c: char) -> bool {
        c.is_alphanumeric() || c == '_' || c == '?' || c == '.' || c == '-' || c == '+'
    }

    pub fn remove_variable(&mut self, name: &str) -> Option<Value<'a>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.remove_variable(name)
    }

    pub fn get_mut(&mut self, name: &str) -> Option<&mut Value<'a>> {
        if name.starts_with("super::") || name.starts_with("global::") {
            // Cannot mutate outer namespace
            return None;
        }
        self.0.get_mut(name)
    }

    pub fn get_str(&self, name: &str) -> Option<types::Str> {
        match name {
            "MWD" => return Some(self.get_minimal_directory()),
            "SWD" => return Some(self.get_simplified_directory()),
            _ => (),
        }
        // If the parsed name contains the '::' pattern, then a namespace was
        // designated. Find it.
        match name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
            Some(("c", variable)) | Some(("color", variable)) => {
                Colors::collect(variable).into_string().map(|s| s.into())
            }
            Some(("x", variable)) | Some(("hex", variable)) => {
                match u8::from_str_radix(variable, 16) {
                    Ok(c) => Some((c as char).to_string().into()),
                    Err(why) => {
                        eprintln!("ion: hex parse error: {}: {}", variable, why);
                        None
                    }
                }
            }
            Some(("env", variable)) => env::var(variable).map(Into::into).ok().map(|s| s),
            Some(("super", _)) | Some(("global", _)) | None => {
                // Otherwise, it's just a simple variable name.
                match self.get_ref(name) {
                    Some(Value::Str(val)) => Some(val.clone()),
                    _ => env::var(name).ok().map(|s| s.into()),
                }
            }
            Some((..)) => {
                eprintln!("ion: unsupported namespace: '{}'", name);
                None
            }
        }
    }

    pub fn get_ref(&self, mut name: &str) -> Option<&Value<'a>> {
        const GLOBAL_NS: &str = "global::";
        const SUPER_NS: &str = "super::";

        let namespace = if name.starts_with(GLOBAL_NS) {
            name = &name[GLOBAL_NS.len()..];
            // Go up as many namespaces as possible
            Namespace::Global
        } else if name.starts_with(SUPER_NS) {
            let mut up = 0;
            while name.starts_with(SUPER_NS) {
                name = &name[SUPER_NS.len()..];
                up += 1;
            }

            Namespace::Specific(up)
        } else {
            Namespace::Any
        };
        self.0.get_ref(name, namespace)
    }
}

impl<'a> Default for Variables<'a> {
    fn default() -> Self {
        let mut map: Scopes<types::Str, Value<'a>> = Scopes::with_capacity(64);
        map.set("HISTORY_SIZE", "1000");
        map.set("HISTFILE_SIZE", "100000");
        map.set(
            "PROMPT",
            "${x::1B}]0;${USER}: \
             ${PWD}${x::07}${c::0x55,bold}${USER}${c::default}:${c::0x4B}${SWD}${c::default}# \
             ${c::reset}",
        );

        // Set the PID, UID, and EUID variables.
        map.set("PID", Value::Str(getpid().ok().map_or("?".into(), |id| id.to_string().into())));
        map.set("UID", Value::Str(getuid().ok().map_or("?".into(), |id| id.to_string().into())));
        map.set("EUID", Value::Str(geteuid().ok().map_or("?".into(), |id| id.to_string().into())));

        // Initialize the HISTFILE variable
        if let Ok(base_dirs) = BaseDirectories::with_prefix("ion") {
            if let Ok(path) = base_dirs.place_data_file("history") {
                map.set("HISTFILE", path.to_str().unwrap_or("?"));
                map.set("HISTFILE_ENABLED", "1");
            }
        }

        // History Timestamps enabled variable, disabled by default
        map.set("HISTORY_TIMESTAMP", "0");

        map.set("HISTORY_IGNORE", array!["no_such_command", "whitespace", "duplicates"]);

        map.set("CDPATH", Array::new());

        // Initialize the HOME variable
        sys_env::home_dir().map_or_else(
            || env::set_var("HOME", "?"),
            |path| env::set_var("HOME", path.to_str().unwrap_or("?")),
        );

        // Initialize the HOST variable
        env::set_var("HOST", &self_sys::get_host_name().unwrap_or_else(|| "?".to_owned()));

        Variables(map)
    }
}

#[cfg(test)]
mod trait_test;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parser::Expander;
    use serial_test_derive::serial;

    struct VariableExpander<'a>(pub Variables<'a>);

    impl<'a> Expander for VariableExpander<'a> {
        fn string(&self, var: &str) -> Option<types::Str> { self.0.get_str(var) }
    }

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::default();
        let expanded = VariableExpander(variables).expand_string("$FOO").join("");
        assert_eq!("", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set("FOO", "BAR");
        let expanded = VariableExpander(variables).expand_string("$FOO").join("");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    #[serial]
    fn minimal_directory_var_should_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log/nix");
        assert_eq!(
            types::Str::from("v/l/nix"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }

    #[test]
    #[serial]
    fn minimal_directory_var_shouldnt_compact_path() {
        let variables = Variables::default();
        env::set_var("PWD", "/var/log");
        assert_eq!(
            types::Str::from("/var/log"),
            variables.get_str("MWD").expect("no value returned"),
        );
    }
}
<|endoftext|>


<commit_before>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_buffer (buf: &[u8]) {
        let fin = buf[0] & 0b1000_0000;
        let rsv = buf[0] & 0b0111_0000;
        let opc = buf[0] & 0b0000_1111;
        let msk = buf[0] & 0b0000_0001;
        let len = buf[1] & 0b0111_1111;
        let mskkey = buf.slice(2, 6);

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, \nbuf {}",
            fin, rsv, msk, opc, len, mskkey, buf.as_slice());
    }

    fn continue_from_buffer(buf: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    let mut stream2 = stream;
    msg.send(&mut stream2);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    let mut stream3 = stream2;
    msg.send(&mut stream3);

    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);

    let mut stream4 = stream3;
    let mut buf = [0, ..100];
    match stream4.read(&mut buf) {
        Ok(nread) => println!("Read {} bytes", nread),
        Err(e) => println!("error reading: {}", e)
    }

    Message::from_buffer(&buf);

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<commit_msg>unmasking a char<commit_after>extern crate "rust-crypto" as rust_crypto;
extern crate serialize;

use std::io::{TcpListener, TcpStream};
use std::io::{Acceptor, Listener};
use std::io::{File, BufferedStream};
use std::string::String;
use std::os;
use std::vec::Vec;

use rust_crypto::sha1::Sha1;
use rust_crypto::digest::Digest;
use serialize::base64::{ToBase64, STANDARD};

use std::io::Timer;
use std::io::timer;
use std::time::duration::Duration;

pub const CR: u8 = b'\r';
pub const LF: u8 = b'\n';
pub const SP: u8 = b' ';
pub const COLON: u8 = b':';
pub const CRLF: &'static [u8] = &[CR,LF];

struct RequestedRoute {
    method: String,
    pathname: String
}

struct ClientHeader {
    key: String,
    value: String
}

enum Payload {
    Text(String),
    Binary(Vec<u8>),
    Empty
}

enum Opcode {
    EmptyOp = 0x0,
    TextOp = 0x1,
    BinaryOp = 0x2,
    CloseOp = 0x8,
}

struct Message {
    payload: Payload,
    opcode: Opcode,
    fin: u8
 }

impl Message {

    fn from_payload (payload: Payload, fin: u8) -> Message {
        let opcode: Opcode = match payload {
            Payload::Text(_) => Opcode::TextOp,
            Payload::Binary(_) => Opcode::BinaryOp,
            Payload::Empty => Opcode::EmptyOp
        };
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn continue_from_payload (payload: Payload) -> Message {
        let opcode = Opcode::EmptyOp;
        let fin = 0x0;
        return Message {payload: payload, opcode: opcode, fin: fin};
    }

    fn send (&self,
            mut stream: &mut BufferedStream<TcpStream>) {
        let msg = match self.payload {
            Payload::Text(ref s) => s.as_bytes(),
            Payload::Binary(ref s) => s.as_slice(),
            Payload::Empty => "".as_bytes(),
        };

        let length = msg.len() as u8;

        println!("fin: {}, msg: {}, opcode: {}", self.fin, msg, self.opcode as u8);

        stream.write_u8(self.fin | self.opcode as u8).unwrap();
        stream.write_u8(length).unwrap();
        stream.write(msg).unwrap();
        stream.flush();
    }

    fn from_buffer (buf: &[u8]) {
        let fin = buf[0] & 0b1000_0000;
        let rsv = buf[0] & 0b0111_0000;
        let opc = buf[0] & 0b0000_1111;
        let msk = buf[0] & 0b0000_0001;
        let len = buf[1] & 0b0111_1111;
        let mskkey = buf.slice(2, 6);

        let firstchar = mskkey[0] ^ buf[6];

        println!(
            "fin {}, rsv {}, msk {}, opcode {}, len {}, mskkey {}, firstchar {}, \nbuf {}",
            fin, rsv, msk, opc, len, mskkey, firstchar as char,  buf.as_slice());
    }

    fn continue_from_buffer(buf: &[u8]) {

    }
}

fn get_header_by_name (header: &[u8], headers: &Vec<ClientHeader>) -> String {
    let mut result = String::new();

    for h in headers.iter() {
        if h.key.as_bytes() == header {
            result = h.value.clone();
            break;
        }
    }

    return result;
}

fn parse_request_line (header: &str) -> RequestedRoute {
    let mut pathname = String::new();
    let mut method = String::new();
    let mut starting = true;
    let mut found_method = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];

        if starting && cbyte != SP {
            method.push_str(ch);
        }
        if starting && cbyte == SP {
            starting = false;
            found_method = true;
            continue;
        }
        if found_method && cbyte != SP {
            pathname.push_str(ch);
        }
        if found_method && cbyte == SP {
            break;
        }

    }

    return RequestedRoute {method: method, pathname: pathname};
}

fn parse_normal_header (header: &str) -> ClientHeader {
    let mut lhs = String::new(); // lhs of ':' in header
    let mut rhs = String::new(); // rhs of ':' in header
    let mut found_colon = false;

    for ch in header.graphemes(true) {
        let cbyte = ch.as_bytes()[0];
        if !found_colon && cbyte == COLON {
            found_colon = true;
            continue;
        }

        if cbyte == CR || cbyte == LF {
            continue;
        }

        if !found_colon {
            lhs.push_str(ch);
        } else {
            rhs.push_str(ch);
        }
    }

    return ClientHeader {
        key:lhs.trim().to_string(),
        value:rhs.trim().to_string()
    };
}

fn get_normal_body (path_on_disk: &str) -> String {
    let path = Path::new(path_on_disk);
    let display = path.display();
    let mut file = match File::open(&path) {
        Ok(f) => f,
        Err(err) => panic!("file error: {}", err)
    };

    let content = match file.read_to_end() {
        Ok(c) => c,
        Err(err) => panic!("{}", err)
    };

    let s = String::from_utf8(content).unwrap();
    return s;
}

fn sec_handshake (from_server: &[u8]) -> String {

    // from rfc6455 [page 6]
    let guid = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    let mut sha = Sha1::new();

    sha.input(from_server);
    sha.input(guid);
    let mut out = [0u8, ..20];
    sha.result(out.as_mut_slice());

    return out.to_base64(STANDARD);
}

fn ws_handshake (mut stream: BufferedStream<TcpStream>,
                 headers: Vec<ClientHeader>) {

    let header_sec_key = b"Sec-WebSocket-Key";

    let from_server = get_header_by_name(header_sec_key, &headers);
    let accept = sec_handshake(from_server.as_bytes());

    let sec_header = format!("Sec-WebSocket-Accept: {}\r\n", accept);

    stream.write(b"HTTP/1.1 101 Switching Protocols\r\n").unwrap();
    stream.write(b"Upgrade: websocket\r\n").unwrap();
    stream.write(b"Connection: Upgrade\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Version: 13\r\n").unwrap();
    stream.write(b"Sec-WebSocket-Protocol: protocolOne\r\n").unwrap();
    stream.write(sec_header.as_bytes()).unwrap();
    stream.write(b"\r\n");

    ws_listen(stream, headers);
}

fn ws_listen(mut stream: BufferedStream<TcpStream>,
             mut headers: Vec<ClientHeader>) {

    let payload = Payload::Text("text ".to_string());
    let msg = Message::from_payload(payload, 0b0000_0000);
    msg.send(&mut stream);

    let payload = Payload::Text("here".to_string());
    let msg = Message::continue_from_payload(payload);
    let mut stream2 = stream;
    msg.send(&mut stream2);

    let payload = Payload::Empty;
    let msg = Message::from_payload(payload, 0b1000_0000);
    let mut stream3 = stream2;
    msg.send(&mut stream3);

    let mut timer = Timer::new().unwrap();
    let interval = Duration::milliseconds(5000);
    timer::sleep(interval);

    let mut stream4 = stream3;
    let mut buf = [0, ..100];
    match stream4.read(&mut buf) {
        Ok(nread) => println!("Read {} bytes", nread),
        Err(e) => println!("error reading: {}", e)
    }

    Message::from_buffer(&buf);

}

fn main () {

    for argument in os::args().iter() {
        println!("arg: {}", argument);
    }

    let addr = "127.0.0.1:8099";

    let listener = TcpListener::bind(addr).unwrap();
    let mut acceptor = listener.listen().unwrap();
    println!("Listening on {}", addr);

    fn handle_client(mut stream: BufferedStream<TcpStream>) {
        let mut body: String = "
You sent it!
".to_string();

        let mut cur_line: String;
        let mut ii = 0u;
        let mut req: RequestedRoute = RequestedRoute {
            pathname: String::new(),
            method: String::new()
        };

        let mut headers: Vec<ClientHeader> = Vec::new();
        loop {
            match stream.read_line() { // XXX: strange unwrap like thing
                Ok(line) => cur_line = line,
                Err(_) => break
            }

            body = body + cur_line + "
";
            if cur_line.as_bytes() == CRLF {
                break;
            }

            if ii == 0u { // the Request-Line is always the first line
                req = parse_request_line(cur_line.as_slice());
                println!("{}", req.pathname);
                ii += 1;
            } else { // this should be  "normal" key-value type header
                headers.push(parse_normal_header(cur_line.as_slice()));
            }

        }

        println!("pathname {} method {}", req.pathname, req.method);

        if req.pathname.as_bytes() == b"/" {
            body = get_normal_body("./html/ws1.html");
        } else if req.pathname.as_bytes() == b"/ws1.js" {
            body = get_normal_body("./html/ws1.js");
        } else if req.pathname.as_bytes() == b"/ws" {
            ws_handshake(stream, headers);
            return;
        }

        let body_length = format!("Content-length: {}", body.len());

        stream.write(b"HTTP/1.1 200 OK\r\n").unwrap();
        stream.write(b"Content-type: text/html\r\n").unwrap();
        stream.write(b"X-header: from bytes\r\n").unwrap();
        stream.write(body_length.as_bytes()).unwrap();
        stream.write(b"\r\n\r\n").unwrap();
        stream.write(body.as_bytes()).unwrap();
        stream.flush().unwrap();

        println!("Done handling acceptor");
    }

    for stream in acceptor.incoming() {
        match stream {
            Err(e) => { println!("connection failed: {}", e) }
            Ok(stream) => spawn(proc() {
                let bs = BufferedStream::new(stream);
                handle_client(bs)
            })
        }
    }

    drop(acceptor);
}
<|endoftext|>


<commit_before>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct MediaType {
    type_: ~str,
    subtype: ~str,
    parameters: ~[(~str, ~str)],
}

impl ToStr for MediaType {
    fn to_str(&self) -> ~str {
        // Idea:
        //let s = ~"";
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = fmt!("%s/%s", self.type_, self.subtype);
        push_parameters(s, self.parameters)
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                if reader.verify_consumed() {
                    None
                } else {
                    Some(MediaType {
                        type_: type_,
                        subtype: subtype,
                        parameters: parameters,
                    })
                }
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        writer.write_token(self.type_);
        writer.write(['/' as u8]);
        writer.write_token(self.subtype);
        writer.write_parameters(self.parameters);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}
<commit_msg>Fix some header parsing logic<commit_after>//! The Content-Type entity header, defined in RFC 2616, Section 14.17.
use headers::serialization_utils::{push_parameters, WriterUtil};
use std::rt::io::{Reader, Writer};

#[deriving(Clone, Eq)]
pub struct MediaType {
    type_: ~str,
    subtype: ~str,
    parameters: ~[(~str, ~str)],
}

impl ToStr for MediaType {
    fn to_str(&self) -> ~str {
        // Idea:
        //let s = ~"";
        //s.push_token(self.type_);
        //s.push_char('/');
        //s.push_token(self.subtype);
        //s.push_parameters(self.parameters);
        //s
        let s = fmt!("%s/%s", self.type_, self.subtype);
        push_parameters(s, self.parameters)
    }
}

impl super::HeaderConvertible for MediaType {
    fn from_stream<T: Reader>(reader: &mut super::HeaderValueByteIterator<T>) -> Option<MediaType> {
        let type_ = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        if reader.next() != Some('/' as u8) {
            return None;
        }
        let subtype = match reader.read_token() {
            Some(v) => v,
            None => return None,
        };
        match reader.read_parameters() {
            // At the time of writing, ``Some(parameters) if reader.verify_consumed()`` was not
            // permitted: "cannot bind by-move into a pattern guard"
            Some(parameters) => {
                if !reader.verify_consumed() {
                    None
                } else {
                    Some(MediaType {
                        type_: type_,
                        subtype: subtype,
                        parameters: parameters,
                    })
                }
            },
            None => None,
        }
    }

    fn to_stream<W: Writer>(&self, writer: &mut W) {
        writer.write_token(self.type_);
        writer.write(['/' as u8]);
        writer.write_token(self.subtype);
        writer.write_parameters(self.parameters);
    }

    fn http_value(&self) -> ~str {
        self.to_str()
    }
}
<|endoftext|>