<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_crypto::hash::HashValue;
use aptos_logger::prelude::*;
use aptos_types::multi_signature::MultiSignature;
use aptos_types::{
    block_info::BlockInfo,
    ledger_info::{LedgerInfo, LedgerInfoWithSignatures},
    transaction::Version,
};
use aptos_vm::AptosVM;
use aptosdb::metrics::API_LATENCY_SECONDS;
use executor::{
    block_executor::BlockExecutor,
    metrics::{
        APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS, APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS,
        APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS,
    },
};
use executor_types::BlockExecutorTrait;
use std::{
    sync::{mpsc, Arc},
    time::{Duration, Instant},
};

pub(crate) fn gen_li_with_sigs(
    block_id: HashValue,
    root_hash: HashValue,
    version: Version,
) -> LedgerInfoWithSignatures {
    let block_info = BlockInfo::new(
        1,        /* epoch */
        0,        /* round, doesn't matter */
        block_id, /* id, doesn't matter */
        root_hash, version, 0,    /* timestamp_usecs, doesn't matter */
        None, /* next_epoch_state */
    );
    let ledger_info = LedgerInfo::new(
        block_info,
        HashValue::zero(), /* consensus_data_hash, doesn't matter */
    );
    LedgerInfoWithSignatures::new(ledger_info, MultiSignature::empty() /* signatures */)
}

pub struct TransactionCommitter {
    executor: Arc<BlockExecutor<AptosVM>>,
    version: Version,
    block_receiver: mpsc::Receiver<(HashValue, HashValue, Instant, Instant, Duration, usize)>,
}

impl TransactionCommitter {
    pub fn new(
        executor: Arc<BlockExecutor<AptosVM>>,
        version: Version,
        block_receiver: mpsc::Receiver<(HashValue, HashValue, Instant, Instant, Duration, usize)>,
    ) -> Self {
        Self {
            version,
            executor,
            block_receiver,
        }
    }

    pub fn run(&mut self) {
        let start_version = self.version;
        info!("Start with version: {}", start_version);

        while let Ok((
            block_id,
            root_hash,
            global_start_time,
            execution_start_time,
            execution_time,
            num_txns,
        )) = self.block_receiver.recv()
        {
            self.version += num_txns as u64;
            let commit_start = std::time::Instant::now();
            let ledger_info_with_sigs = gen_li_with_sigs(block_id, root_hash, self.version);
            self.executor
                .commit_blocks(vec![block_id], ledger_info_with_sigs)
                .unwrap();

            report_block(
                start_version,
                self.version,
                global_start_time,
                execution_start_time,
                execution_time,
                Instant::now().duration_since(commit_start),
                num_txns,
            );
        }
    }
}

fn report_block(
    start_version: Version,
    version: Version,
    global_start_time: Instant,
    execution_start_time: Instant,
    execution_time: Duration,
    commit_time: Duration,
    block_size: usize,
) {
    let total_versions = (version - start_version) as f64;
    info!(
        "Version: {}. latency: {} ms, execute time: {} ms. commit time: {} ms. TPS: {:.0}. Accumulative TPS: {:.0}",
        version,
        Instant::now().duration_since(execution_start_time).as_millis(),
        execution_time.as_millis(),
        commit_time.as_millis(),
        block_size as f64 / (std::cmp::max(execution_time, commit_time)).as_secs_f64(),
        total_versions / global_start_time.elapsed().as_secs_f64(),
    );
    info!(
            "Accumulative total: VM time: {:.0} secs, executor time: {:.0} secs, commit time: {:.0} secs, DB commit time: {:.0} secs",
            APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum(),
            APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.get_sample_sum() - APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum(),
            APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS.get_sample_sum(),
            API_LATENCY_SECONDS.get_metric_with_label_values(&["save_transactions", "Ok"]).expect("must exist.").get_sample_sum(),
        );
    const NANOS_PER_SEC: f64 = 1_000_000_000.0;
    info!(
            "Accumulative per transaction: VM time: {:.0} ns, executor time: {:.0} ns, commit time: {:.0} ns, DB commit time: {:.0} ns",
            APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum() * NANOS_PER_SEC
                / total_versions,
            (APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.get_sample_sum() - APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum()) * NANOS_PER_SEC
                / total_versions,
            APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS.get_sample_sum() * NANOS_PER_SEC
                / total_versions,
            API_LATENCY_SECONDS.get_metric_with_label_values(&["save_transactions", "Ok"]).expect("must exist.").get_sample_sum() * NANOS_PER_SEC
                / total_versions,
        );
}
<commit_msg>[Executor-benchmark] Update benchmark to use async commit. (#3028)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_crypto::hash::HashValue;
use aptos_logger::prelude::*;
use aptos_types::{
    block_info::BlockInfo,
    ledger_info::{LedgerInfo, LedgerInfoWithSignatures},
    multi_signature::MultiSignature,
    transaction::Version,
};
use aptos_vm::AptosVM;
use aptosdb::metrics::API_LATENCY_SECONDS;
use executor::{
    block_executor::BlockExecutor,
    metrics::{
        APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS, APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS,
        APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS,
    },
};
use executor_types::BlockExecutorTrait;
use std::{
    sync::{mpsc, Arc},
    time::{Duration, Instant},
};

pub(crate) fn gen_li_with_sigs(
    block_id: HashValue,
    root_hash: HashValue,
    version: Version,
) -> LedgerInfoWithSignatures {
    let block_info = BlockInfo::new(
        1,        /* epoch */
        0,        /* round, doesn't matter */
        block_id, /* id, doesn't matter */
        root_hash, version, 0,    /* timestamp_usecs, doesn't matter */
        None, /* next_epoch_state */
    );
    let ledger_info = LedgerInfo::new(
        block_info,
        HashValue::zero(), /* consensus_data_hash, doesn't matter */
    );
    LedgerInfoWithSignatures::new(ledger_info, MultiSignature::empty() /* signatures */)
}

pub struct TransactionCommitter {
    executor: Arc<BlockExecutor<AptosVM>>,
    version: Version,
    block_receiver: mpsc::Receiver<(HashValue, HashValue, Instant, Instant, Duration, usize)>,
}

impl TransactionCommitter {
    pub fn new(
        executor: Arc<BlockExecutor<AptosVM>>,
        version: Version,
        block_receiver: mpsc::Receiver<(HashValue, HashValue, Instant, Instant, Duration, usize)>,
    ) -> Self {
        Self {
            version,
            executor,
            block_receiver,
        }
    }

    pub fn run(&mut self) {
        let start_version = self.version;
        info!("Start with version: {}", start_version);

        while let Ok((
            block_id,
            root_hash,
            global_start_time,
            execution_start_time,
            execution_time,
            num_txns,
        )) = self.block_receiver.recv()
        {
            self.version += num_txns as u64;
            let commit_start = std::time::Instant::now();
            let ledger_info_with_sigs = gen_li_with_sigs(block_id, root_hash, self.version);
            self.executor
                .commit_blocks_ext(vec![block_id], ledger_info_with_sigs, false)
                .unwrap();

            report_block(
                start_version,
                self.version,
                global_start_time,
                execution_start_time,
                execution_time,
                Instant::now().duration_since(commit_start),
                num_txns,
            );
        }
    }
}

fn report_block(
    start_version: Version,
    version: Version,
    global_start_time: Instant,
    execution_start_time: Instant,
    execution_time: Duration,
    commit_time: Duration,
    block_size: usize,
) {
    let total_versions = (version - start_version) as f64;
    info!(
        "Version: {}. latency: {} ms, execute time: {} ms. commit time: {} ms. TPS: {:.0}. Accumulative TPS: {:.0}",
        version,
        Instant::now().duration_since(execution_start_time).as_millis(),
        execution_time.as_millis(),
        commit_time.as_millis(),
        block_size as f64 / (std::cmp::max(execution_time, commit_time)).as_secs_f64(),
        total_versions / global_start_time.elapsed().as_secs_f64(),
    );
    info!(
            "Accumulative total: VM time: {:.0} secs, executor time: {:.0} secs, commit time: {:.0} secs, DB commit time: {:.0} secs",
            APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum(),
            APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.get_sample_sum() - APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum(),
            APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS.get_sample_sum(),
            API_LATENCY_SECONDS.get_metric_with_label_values(&["save_transactions", "Ok"]).expect("must exist.").get_sample_sum(),
        );
    const NANOS_PER_SEC: f64 = 1_000_000_000.0;
    info!(
            "Accumulative per transaction: VM time: {:.0} ns, executor time: {:.0} ns, commit time: {:.0} ns, DB commit time: {:.0} ns",
            APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum() * NANOS_PER_SEC
                / total_versions,
            (APTOS_EXECUTOR_EXECUTE_BLOCK_SECONDS.get_sample_sum() - APTOS_EXECUTOR_VM_EXECUTE_BLOCK_SECONDS.get_sample_sum()) * NANOS_PER_SEC
                / total_versions,
            APTOS_EXECUTOR_COMMIT_BLOCKS_SECONDS.get_sample_sum() * NANOS_PER_SEC
                / total_versions,
            API_LATENCY_SECONDS.get_metric_with_label_values(&["save_transactions", "Ok"]).expect("must exist.").get_sample_sum() * NANOS_PER_SEC
                / total_versions,
        );
}
<|endoftext|>


<commit_before>use callback::{AsWrapper, IntoCallback, Wrapper};
use handlers::keyboard::KeyPattern;
use handlers::workspaces::modes::{AnyModeConfig, AnyModeWrap, Mode};
use slog;
use slog_scope;
use wlc::{Callback, Geometry, Key, KeyState, Modifiers, Point, ResizeEdge, View, ViewState, WeakView};

/// A `Mode` that lets you pull one `View` into fullscreen operation while
/// letting another wrapped `Mode` handle the rest
pub struct Fullscreen {
    active: Option<WeakView>,
    mode: Box<AnyModeWrap>,
    keys: KeyPatterns,
    logger: slog::Logger,
}

/// Configuration of `Fullscreen`
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
pub struct FullscreenConfig {
    /// Configuration of the wrapped `Mode`
    pub mode: Box<AnyModeConfig>,
    /// Key configuration
    pub keys: KeyPatterns,
}

/// `KeyPattern`s toggling fullscreen
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Deserialize)]
pub struct KeyPatterns {
    /// Toggle fullscreen operation for the currently focused `View`
    pub toggle: Option<KeyPattern>,
}

/// Convinient type alias for a wrapped `Fullscreen`
pub type FullscreenWrap = Wrapper<Fullscreen>;

impl AsWrapper for Fullscreen {
    fn child(&mut self) -> Option<&mut Callback> {
        Some(&mut self.mode)
    }
}

impl Mode for Wrapper<Fullscreen> {
    type Arguments = FullscreenConfig;

    fn new(arguments: Self::Arguments) -> Self {
        Fullscreen {
                active: None,
                mode: Box::new(AnyModeWrap::new(*arguments.mode)),
                keys: arguments.keys,
                logger: slog_scope::logger().new(o!("instance" => "Fullscreen")),
            }
            .into_callback()
    }

    fn len(&self) -> usize {
        self.mode.len() + self.active.as_ref().map(|_| 1).unwrap_or(0)
    }
}

impl Callback for Wrapper<Fullscreen> {
    fn keyboard_key(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, key: Key,
                    state: KeyState)
                    -> bool {
        if let Some(view) = view {
            match Some(KeyPattern::new(state, modifiers.mods, key)) {
                x if x == self.keys.toggle => {
                    let active = self.has_active();
                    if active {
                        self.set_fullscreen(None);
                    } else {
                        self.set_fullscreen(Some(view));
                    }
                    true
                }
                _ => self.mode.keyboard_key(Some(view), time, modifiers, key, state),
            }
        } else {
            self.mode.keyboard_key(None, time, modifiers, key, state)
        }
    }

    fn view_request_state(&mut self, view: &View, state: ViewState::Flags, toggle: bool) {
        match state {
            x if x.contains(ViewState::Fullscreen) => {
                if toggle {
                    self.set_fullscreen(Some(view))
                } else if self.active == Some(view.weak_reference()) {
                    self.set_fullscreen(None)
                }
            }
            _ => self.mode.view_request_state(view, state, toggle),
        };
    }
}

impl Fullscreen {
    fn has_active(&self) -> bool {
        self.active.as_ref().is_some()
    }

    fn set_fullscreen(&mut self, view: Option<&View>) {
        {
            let active = self.active.clone();
            if let Some(active) = active {
                debug!(self.logger, "Un-fullscreening {:?}", active);
                active.run(|active_view| {
                    active_view.set_state(ViewState::Fullscreen, false);
                    self.mode.view_created(active_view);
                });
            }

            if let Some(view) = view {
                debug!(self.logger, "Fullscreening {:?}", view);
                self.mode.view_destroyed(view);
                view.set_geometry(ResizeEdge::Null,
                                  Geometry {
                                      origin: Point { x: 0, y: 0 },
                                      size: view.output().virtual_resolution(),
                                  });
                view.set_state(ViewState::Fullscreen, true);
                view.bring_to_front();
            }
        }

        self.active = view.map(|view| view.weak_reference());
    }
}
<commit_msg>Rework fullscreening<commit_after>use callback::{AsWrapper, IntoCallback, Wrapper};
use handlers::keyboard::KeyPattern;
use handlers::workspaces::modes::{AnyModeConfig, AnyModeWrap, Mode};
use slog;
use slog_scope;
use wlc::{Callback, Geometry, Key, KeyState, Modifiers, Point, ResizeEdge, View, ViewState, WeakView};

/// A `Mode` that lets you pull one `View` into fullscreen operation while
/// letting another wrapped `Mode` handle the rest
pub struct Fullscreen {
    active: Option<(WeakView, Geometry)>,
    mode: Box<AnyModeWrap>,
    keys: KeyPatterns,
    logger: slog::Logger,
}

/// Configuration of `Fullscreen`
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
pub struct FullscreenConfig {
    /// Configuration of the wrapped `Mode`
    pub mode: Box<AnyModeConfig>,
    /// Key configuration
    pub keys: KeyPatterns,
}

/// `KeyPattern`s toggling fullscreen
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Deserialize)]
pub struct KeyPatterns {
    /// Toggle fullscreen operation for the currently focused `View`
    pub toggle: Option<KeyPattern>,
}

/// Convinient type alias for a wrapped `Fullscreen`
pub type FullscreenWrap = Wrapper<Fullscreen>;

impl AsWrapper for Fullscreen {
    fn child(&mut self) -> Option<&mut Callback> {
        Some(&mut self.mode)
    }
}

impl Mode for Wrapper<Fullscreen> {
    type Arguments = FullscreenConfig;

    fn new(arguments: Self::Arguments) -> Self {
        Fullscreen {
                active: None,
                mode: Box::new(AnyModeWrap::new(*arguments.mode)),
                keys: arguments.keys,
                logger: slog_scope::logger().new(o!("instance" => "Fullscreen")),
            }
            .into_callback()
    }

    fn len(&self) -> usize {
        self.mode.len() + self.active.as_ref().map(|_| 1).unwrap_or(0)
    }
}

impl Callback for Wrapper<Fullscreen> {
    fn keyboard_key(&mut self, view: Option<&View>, time: u32, modifiers: Modifiers, key: Key,
                    state: KeyState)
                    -> bool {
        if let Some(view) = view {
            match Some(KeyPattern::new(state, modifiers.mods, key)) {
                x if x == self.keys.toggle => {
                    let active = self.has_active();
                    if active {
                        self.set_fullscreen(None);
                    } else {
                        self.set_fullscreen(Some(view));
                    }
                    true
                }
                _ => self.mode.keyboard_key(Some(view), time, modifiers, key, state),
            }
        } else {
            self.mode.keyboard_key(None, time, modifiers, key, state)
        }
    }

    fn view_request_state(&mut self, view: &View, state: ViewState::Flags, toggle: bool) {
        match state {
            x if x.contains(ViewState::Fullscreen) => {
                if self.active.is_some() {
                    self.set_fullscreen(None)
                } else if toggle {
                    self.set_fullscreen(Some(view))
                }
            }
            _ => self.mode.view_request_state(view, state, toggle),
        };
    }
}

impl Fullscreen {
    fn has_active(&self) -> bool {
        self.active.as_ref().is_some()
    }

    fn set_fullscreen(&mut self, view: Option<&View>) {
        if let Some((active, geo)) = self.active.clone() {
            debug!(self.logger, "Un-fullscreening {:?}", active);
            active.run(|active_view| {
                active_view.set_state(ViewState::Fullscreen, false);
                active_view.set_geometry(ResizeEdge::Null, geo);
            });
        }
        self.active = None;

        if let Some(view) = view {
            debug!(self.logger, "Fullscreening {:?}", view);

            let geo = view.geometry();
            view.set_geometry(ResizeEdge::Null,
                              Geometry {
                                  origin: Point { x: 0, y: 0 },
                                  size: view.output().virtual_resolution(),
                              });
            view.set_state(ViewState::Fullscreen, true);
            view.bring_to_front();

            self.active = Some((view.weak_reference(), geo));
        }
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// 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::fmt::Debug;
use std::hash::Hash;

mod error;
mod inputs_private;
mod iterators_private;
mod macros;
mod parser;
mod parser_state;
mod token;

/// A `mod` containing the `Input`-related constructs.
pub mod inputs {
    pub use super::inputs_private::{Input, Position, Span, StringInput};
}

/// A `mod` containing iterators and constructs to aid in parser output manipulation.
pub mod iterators {
    pub use super::iterators_private::{Pair, Pairs, TokenIterator};
}

/// A `trait` which parser rules must implement.
pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}
impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}

pub use error::Error;
pub use parser::Parser;
pub use parser_state::{state, ParserState};
pub use token::Token;
<commit_msg>Added some documentation to RuleType to explain why it works<commit_after>// pest. The Elegant Parser
// Copyright (C) 2017  Dragoș Tiselice
//
// 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::fmt::Debug;
use std::hash::Hash;

mod error;
mod inputs_private;
mod iterators_private;
mod macros;
mod parser;
mod parser_state;
mod token;

/// A `mod` containing the `Input`-related constructs.
pub mod inputs {
    pub use super::inputs_private::{Input, Position, Span, StringInput};
}

/// A `mod` containing iterators and constructs to aid in parser output manipulation.
pub mod iterators {
    pub use super::iterators_private::{Pair, Pairs, TokenIterator};
}

/// A `trait` which parser rules must implement.
///
/// This trait is setup so that any struct that implements all of its required traits will
/// automatically implement this trait as well.
///
/// This is essentially a [trait alias](https://github.com/rust-lang/rfcs/pull/1733). When trait
/// aliases are implemented, this may be replaced by one.
pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}
impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}

pub use error::Error;
pub use parser::Parser;
pub use parser_state::{state, ParserState};
pub use token::Token;
<|endoftext|>


<commit_before>/*
    Copyright (c) 2015, Alex Frappier Lachapelle
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::env;

extern crate hyper;
use hyper::header::Headers;

use utils;

////////////////////////////////////////////////////////////
//                        Structs                         //
////////////////////////////////////////////////////////////

pub struct PushConfig {
    pub trello_api_token:         String,
    pub trello_api_list_id:       String,
    pub trello_api_build_pass_id: String,
    pub trello_api_build_fail_id: String,
    pub card_title:               String,
    pub card_desc:                String,
}

////////////////////////////////////////////////////////////
//                         Impls                          //
////////////////////////////////////////////////////////////

impl PushConfig {
    pub fn fill(cli_card_title:    String,
                cli_card_desc:     String,
                cli_build_pass_id: String,
                cli_build_fail_id: String,
                cli_list_id:       String,
                cli_api_token:     String) -> Result<PushConfig, &'static str> {

        let mut tmp_trello_api_token         = String::new();
        let mut tmp_trello_api_list_id       = String::new();
        let mut tmp_trello_api_build_pass_id = String::new();
        let mut tmp_trello_api_build_fail_id = String::new();

        //NOTE: No need to check card title and card desc

        //Get build pass id from env var (if not given as a cli option, fail if not in env var)
        if cli_build_pass_id.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_BUILD_PASS_ID") {
                Ok(val)  => {tmp_trello_api_build_pass_id = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_BUILD_PASS_ID\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_build_pass_id = cli_build_pass_id;
        }

        //Get build fail id from env var (if not given as a cli option, fail if not in env var)
        if cli_build_fail_id.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_BUILD_FAIL_ID") {
                Ok(val)  => {tmp_trello_api_build_fail_id = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_BUILD_FAIL_ID\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_build_fail_id = cli_build_fail_id;
        }

        //Get card list id from env var (if not given as a cli option, fail if not in env var)
        if cli_list_id.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_LIST_ID") {
                Ok(val)  => {tmp_trello_api_list_id = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_LIST_ID\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_list_id = cli_list_id;
        }

        //Get api token from env var (if not given as a cli option, fail if not in env var)
        if cli_api_token.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_TOKEN") {
                Ok(val)  => {tmp_trello_api_token = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_TOKEN\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_token = cli_api_token;
        }

        Ok(PushConfig {
            trello_api_token:         tmp_trello_api_token,
            trello_api_list_id:       tmp_trello_api_list_id,
            trello_api_build_pass_id: tmp_trello_api_build_pass_id,
            trello_api_build_fail_id: tmp_trello_api_build_fail_id,
            card_title:               cli_card_title,
            card_desc:                cli_card_desc
        })
    }
}

////////////////////////////////////////////////////////////
//                       Functions                        //
////////////////////////////////////////////////////////////

pub fn push(api_key: String, is_pass: bool, push_data: PushConfig) -> Result<(), &'static str> {

    //Setup push packet header.
    let     api_call      = format!("https://api.trello.com/1/cards");
    let mut response_body = String::new();
    let mut header        = Headers::new();

    header.set_raw("key",      vec![api_key.into_bytes()]);//
    header.set_raw("token",    vec![push_data.trello_api_token.into_bytes()]);//
    header.set_raw("name",     vec![push_data.card_title.into_bytes()]);//
    header.set_raw("desc",     vec![push_data.card_desc.into_bytes()]);//
    header.set_raw("idList",   vec![push_data.trello_api_list_id.into_bytes()]);//
    header.set_raw("due",      vec![b"null".to_vec()]);//
    header.set_raw("pos",      vec![b"top".to_vec()]);//

    if is_pass {
        header.set_raw("idLabels", vec![push_data.trello_api_build_pass_id.into_bytes()]);//
    } else {
        header.set_raw("idLabels", vec![push_data.trello_api_build_fail_id.into_bytes()]);//
    }

    //Send off the packet
    match utils::rest_api_call_post_with_header(&api_call, header) {
        Ok(_response_body) => {
            response_body = _response_body;
            Ok(())
        }
        Err(err)           => {
            Err(err)
        }
    }
}

<commit_msg>Fixed card pushing<commit_after>/*
    Copyright (c) 2015, Alex Frappier Lachapelle
    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
    ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

use std::env;

extern crate hyper;
use hyper::header::Headers;

use utils;

////////////////////////////////////////////////////////////
//                        Structs                         //
////////////////////////////////////////////////////////////

pub struct PushConfig {
    pub trello_api_token:         String,
    pub trello_api_list_id:       String,
    pub trello_api_build_pass_id: String,
    pub trello_api_build_fail_id: String,
    pub card_title:               String,
    pub card_desc:                String,
}

////////////////////////////////////////////////////////////
//                         Impls                          //
////////////////////////////////////////////////////////////

impl PushConfig {
    pub fn fill(cli_card_title:    String,
                cli_card_desc:     String,
                cli_build_pass_id: String,
                cli_build_fail_id: String,
                cli_list_id:       String,
                cli_api_token:     String) -> Result<PushConfig, &'static str> {

        let mut tmp_trello_api_token         = String::new();
        let mut tmp_trello_api_list_id       = String::new();
        let mut tmp_trello_api_build_pass_id = String::new();
        let mut tmp_trello_api_build_fail_id = String::new();

        //NOTE: No need to check card title and card desc

        //Get build pass id from env var (if not given as a cli option, fail if not in env var)
        if cli_build_pass_id.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_BUILD_PASS_ID") {
                Ok(val)  => {tmp_trello_api_build_pass_id = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_BUILD_PASS_ID\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_build_pass_id = cli_build_pass_id;
        }

        //Get build fail id from env var (if not given as a cli option, fail if not in env var)
        if cli_build_fail_id.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_BUILD_FAIL_ID") {
                Ok(val)  => {tmp_trello_api_build_fail_id = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_BUILD_FAIL_ID\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_build_fail_id = cli_build_fail_id;
        }

        //Get card list id from env var (if not given as a cli option, fail if not in env var)
        if cli_list_id.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_LIST_ID") {
                Ok(val)  => {tmp_trello_api_list_id = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_LIST_ID\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_list_id = cli_list_id;
        }

        //Get api token from env var (if not given as a cli option, fail if not in env var)
        if cli_api_token.is_empty() {
            //If empty check env var.
            match env::var("TRELLO_API_TOKEN") {
                Ok(val)  => {tmp_trello_api_token = val;}
                Err(_) => {return Err("Error getting the \"TRELLO_API_TOKEN\" environment variable, either undefined or value not in Unicode");}
            }
        } else {
            tmp_trello_api_token = cli_api_token;
        }

        Ok(PushConfig {
            trello_api_token:         tmp_trello_api_token,
            trello_api_list_id:       tmp_trello_api_list_id,
            trello_api_build_pass_id: tmp_trello_api_build_pass_id,
            trello_api_build_fail_id: tmp_trello_api_build_fail_id,
            card_title:               cli_card_title,
            card_desc:                cli_card_desc
        })
    }
}

////////////////////////////////////////////////////////////
//                       Functions                        //
////////////////////////////////////////////////////////////

pub fn push(api_key: String, is_pass: bool, push_data: PushConfig) -> Result<(), &'static str> {

    //Setup push packet header.

    let label: String;
    if is_pass {
        label = push_data.trello_api_build_pass_id;
    } else {
        label = push_data.trello_api_build_fail_id;
    }

    let     api_call      = format!("https://api.trello.com/1/cards?key={}&token={}&idList={}&name={}&desc={}&idLabels={}&due=null&pos=top",
                                    api_key,
                                    push_data.trello_api_token,
                                    push_data.trello_api_list_id,
                                    push_data.card_title,
                                    push_data.card_desc,
                                    label);
    let mut response_body = String::new();
    let mut header        = Headers::new();

    //Send off the packet
    match utils::rest_api_call_post_with_header(&api_call, header) {
        Ok(_response_body) => {
            response_body = _response_body;
            Ok(())
        }
        Err(err)           => {
            Err(err)
        }
    }
}

<|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/. */

//! An implementation of the [CORS preflight cache](https://fetch.spec.whatwg.org/#cors-preflight-cache)
//! For now this library is XHR-specific.
//! For stuff involving `<img>`, `<iframe>`, `<form>`, etc please check what
//! the request mode should be and compare with the fetch spec
//! This library will eventually become the core of the Fetch crate
//! with CORSRequest being expanded into FetchRequest (etc)

use hyper::method::Method;
use std::ascii::AsciiExt;
use std::sync::mpsc::{Sender, Receiver, channel};
use time;
use time::{now, Timespec};
use url::Url;

/// Union type for CORS cache entries
///
/// Each entry might pertain to a header or method
#[derive(Clone)]
pub enum HeaderOrMethod {
    HeaderData(String),
    MethodData(Method)
}

impl HeaderOrMethod {
    fn match_header(&self, header_name: &str) -> bool {
        match *self {
            HeaderOrMethod::HeaderData(ref s) => s.eq_ignore_ascii_case(header_name),
            _ => false
        }
    }

    fn match_method(&self, method: &Method) -> bool {
        match *self {
            HeaderOrMethod::MethodData(ref m) => m == method,
            _ => false
        }
    }
}

/// An entry in the CORS cache
#[derive(Clone)]
pub struct CORSCacheEntry {
    pub origin: Url,
    pub url: Url,
    pub max_age: u32,
    pub credentials: bool,
    pub header_or_method: HeaderOrMethod,
    created: Timespec
}

impl CORSCacheEntry {
    fn new(origin: Url, url: Url, max_age: u32, credentials: bool,
            header_or_method: HeaderOrMethod) -> CORSCacheEntry {
        CORSCacheEntry {
            origin: origin,
            url: url,
            max_age: max_age,
            credentials: credentials,
            header_or_method: header_or_method,
            created: time::now().to_timespec()
        }
    }
}

/// Properties of Request required to cache match.
pub struct CacheRequestDetails {
    pub origin: Url,
    pub destination: Url,
    pub credentials: bool
}

/// Trait for a generic CORS Cache
pub trait CORSCache {
    /// [Clear the cache](https://fetch.spec.whatwg.org/#concept-cache-clear)
    fn clear (&mut self, request: CacheRequestDetails);

    /// Remove old entries
    fn cleanup(&mut self);

    /// Returns true if an entry with a
    /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found
    fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool;

    /// Updates max age if an entry for a
    /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found.
    ///
    /// If not, it will insert an equivalent entry
    fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool;

    /// Returns true if an entry with a
    /// [matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found
    fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool;

    /// Updates max age if an entry for
    /// [a matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found.
    ///
    /// If not, it will insert an equivalent entry
    fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool;
    /// Insert an entry
    fn insert(&mut self, entry: CORSCacheEntry);
}

/// A simple, vector-based CORS Cache
#[derive(Clone)]
pub struct BasicCORSCache(Vec<CORSCacheEntry>);

impl BasicCORSCache {
    fn find_entry_by_header<'a>(&'a mut self, request: &CacheRequestDetails,
                                header_name: &str) -> Option<&'a mut CORSCacheEntry> {
        self.cleanup();
        let BasicCORSCache(ref mut buf) = *self;
        buf.iter_mut().find(|e| e.origin.scheme == request.origin.scheme &&
                                e.origin.host() == request.origin.host() &&
                                e.origin.port() == request.origin.port() &&
                                e.url == request.destination &&
                                e.credentials == request.credentials &&
                                e.header_or_method.match_header(header_name))
    }

    fn find_entry_by_method<'a>(&'a mut self, request: &CacheRequestDetails,
                                method: Method) -> Option<&'a mut CORSCacheEntry> {
        // we can take the method from CORSRequest itself
        self.cleanup();
        let BasicCORSCache(ref mut buf) = *self;
        buf.iter_mut().find(|e| e.origin.scheme == request.origin.scheme &&
                                e.origin.host() == request.origin.host() &&
                                e.origin.port() == request.origin.port() &&
                                e.url == request.destination &&
                                e.credentials == request.credentials &&
                                e.header_or_method.match_method(&method))
    }
}

impl CORSCache for BasicCORSCache {
    /// https://fetch.spec.whatwg.org/#concept-cache-clear
    #[allow(dead_code)]
    fn clear (&mut self, request: CacheRequestDetails) {
        let BasicCORSCache(buf) = self.clone();
        let new_buf: Vec<CORSCacheEntry> =
            buf.into_iter().filter(|e| e.origin == request.origin && request.destination == e.url).collect();
        *self = BasicCORSCache(new_buf);
    }

    // Remove old entries
    fn cleanup(&mut self) {
        let BasicCORSCache(buf) = self.clone();
        let now = time::now().to_timespec();
        let new_buf: Vec<CORSCacheEntry> = buf.into_iter()
                                              .filter(|e| now.sec > e.created.sec + e.max_age as i64)
                                              .collect();
        *self = BasicCORSCache(new_buf);
    }

    fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
        self.find_entry_by_header(&request, header_name).is_some()
    }

    fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool {
        match self.find_entry_by_header(&request, header_name).map(|e| e.max_age = new_max_age) {
            Some(_) => true,
            None => {
                self.insert(CORSCacheEntry::new(request.origin, request.destination, new_max_age,
                                                request.credentials,
                                                HeaderOrMethod::HeaderData(header_name.to_owned())));
                false
            }
        }
    }

    fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
        self.find_entry_by_method(&request, method).is_some()
    }

    fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool {
        match self.find_entry_by_method(&request, method.clone()).map(|e| e.max_age = new_max_age) {
            Some(_) => true,
            None => {
                self.insert(CORSCacheEntry::new(request.origin, request.destination, new_max_age,
                                                request.credentials, HeaderOrMethod::MethodData(method)));
                false
            }
        }
    }

    fn insert(&mut self, entry: CORSCacheEntry) {
        self.cleanup();
        let BasicCORSCache(ref mut buf) = *self;
        buf.push(entry);
    }
}

/// Various messages that can be sent to a CORSCacheTask
pub enum CORSCacheTaskMsg {
    Clear(CacheRequestDetails, Sender<()>),
    Cleanup(Sender<()>),
    MatchHeader(CacheRequestDetails, String, Sender<bool>),
    MatchHeaderUpdate(CacheRequestDetails, String, u32, Sender<bool>),
    MatchMethod(CacheRequestDetails, Method, Sender<bool>),
    MatchMethodUpdate(CacheRequestDetails, Method, u32, Sender<bool>),
    Insert(CORSCacheEntry, Sender<()>),
    ExitMsg
}

/// A Sender to a CORSCacheTask
///
/// This can be used as a CORS Cache.
/// The methods on this type block until they can run, and it behaves similar to a mutex
pub type CORSCacheSender = Sender<CORSCacheTaskMsg>;

impl CORSCache for CORSCacheSender {
    fn clear (&mut self, request: CacheRequestDetails) {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::Clear(request, tx));
        let _ = rx.recv();
    }

    fn cleanup(&mut self) {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::Cleanup(tx));
        let _ = rx.recv();
    }

    fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchHeader(request, header_name.to_owned(), tx));
        rx.recv().unwrap_or(false)
    }

    fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchHeaderUpdate(request, header_name.to_owned(), new_max_age, tx));
        rx.recv().unwrap_or(false)
    }

    fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchMethod(request, method, tx));
        rx.recv().unwrap_or(false)
    }

    fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchMethodUpdate(request, method, new_max_age, tx));
        rx.recv().unwrap_or(false)
    }

    fn insert(&mut self, entry: CORSCacheEntry) {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::Insert(entry, tx));
        let _ = rx.recv();
    }
}

/// A simple task-based CORS Cache that can be sent messages
///
/// #Example
/// ```ignore
/// let task = CORSCacheTask::new();
/// let builder = TaskBuilder::new().named("XHRTask");
/// let mut sender = task.sender();
/// builder.spawn(move || { task.run() });
/// sender.insert(CORSCacheEntry::new(/* parameters here */));
/// ```
pub struct CORSCacheTask {
    receiver: Receiver<CORSCacheTaskMsg>,
    cache: BasicCORSCache,
    sender: CORSCacheSender
}

impl CORSCacheTask {
    pub fn new() -> CORSCacheTask {
        let (tx, rx) = channel();
        CORSCacheTask {
            receiver: rx,
            cache: BasicCORSCache(vec![]),
            sender: tx
        }
    }

    /// Provides a sender to the cache task
    pub fn sender(&self) -> CORSCacheSender {
        self.sender.clone()
    }

    /// Runs the cache task
    /// This blocks the current task, so it is advised
    /// to spawn a new task for this
    /// Send ExitMsg to the associated Sender to exit
    pub fn run(&mut self) {
        loop {
            match self.receiver.recv().unwrap() {
                CORSCacheTaskMsg::Clear(request, tx) => {
                    self.cache.clear(request);
                    tx.send(());
                },
                CORSCacheTaskMsg::Cleanup(tx) => {
                    self.cache.cleanup();
                    tx.send(());
                },
                CORSCacheTaskMsg::MatchHeader(request, header, tx) => {
                    tx.send(self.cache.match_header(request, &header));
                },
                CORSCacheTaskMsg::MatchHeaderUpdate(request, header, new_max_age, tx) => {
                    tx.send(self.cache.match_header_and_update(request, &header, new_max_age));
                },
                CORSCacheTaskMsg::MatchMethod(request, method, tx) => {
                    tx.send(self.cache.match_method(request, method));
                },
                CORSCacheTaskMsg::MatchMethodUpdate(request, method, new_max_age, tx) => {
                    tx.send(self.cache.match_method_and_update(request, method, new_max_age));
                },
                CORSCacheTaskMsg::Insert(entry, tx) => {
                    self.cache.insert(entry);
                    tx.send(());
                },
                CORSCacheTaskMsg::ExitMsg => break
            }
        }
    }
}
<commit_msg>DRY out conditional logic in CORS header matching<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/. */

//! An implementation of the [CORS preflight cache](https://fetch.spec.whatwg.org/#cors-preflight-cache)
//! For now this library is XHR-specific.
//! For stuff involving `<img>`, `<iframe>`, `<form>`, etc please check what
//! the request mode should be and compare with the fetch spec
//! This library will eventually become the core of the Fetch crate
//! with CORSRequest being expanded into FetchRequest (etc)

use hyper::method::Method;
use std::ascii::AsciiExt;
use std::sync::mpsc::{Sender, Receiver, channel};
use time;
use time::{now, Timespec};
use url::Url;

/// Union type for CORS cache entries
///
/// Each entry might pertain to a header or method
#[derive(Clone)]
pub enum HeaderOrMethod {
    HeaderData(String),
    MethodData(Method)
}

impl HeaderOrMethod {
    fn match_header(&self, header_name: &str) -> bool {
        match *self {
            HeaderOrMethod::HeaderData(ref s) => s.eq_ignore_ascii_case(header_name),
            _ => false
        }
    }

    fn match_method(&self, method: &Method) -> bool {
        match *self {
            HeaderOrMethod::MethodData(ref m) => m == method,
            _ => false
        }
    }
}

/// An entry in the CORS cache
#[derive(Clone)]
pub struct CORSCacheEntry {
    pub origin: Url,
    pub url: Url,
    pub max_age: u32,
    pub credentials: bool,
    pub header_or_method: HeaderOrMethod,
    created: Timespec
}

impl CORSCacheEntry {
    fn new(origin: Url, url: Url, max_age: u32, credentials: bool,
            header_or_method: HeaderOrMethod) -> CORSCacheEntry {
        CORSCacheEntry {
            origin: origin,
            url: url,
            max_age: max_age,
            credentials: credentials,
            header_or_method: header_or_method,
            created: time::now().to_timespec()
        }
    }
}

/// Properties of Request required to cache match.
pub struct CacheRequestDetails {
    pub origin: Url,
    pub destination: Url,
    pub credentials: bool
}

/// Trait for a generic CORS Cache
pub trait CORSCache {
    /// [Clear the cache](https://fetch.spec.whatwg.org/#concept-cache-clear)
    fn clear (&mut self, request: CacheRequestDetails);

    /// Remove old entries
    fn cleanup(&mut self);

    /// Returns true if an entry with a
    /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found
    fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool;

    /// Updates max age if an entry for a
    /// [matching header](https://fetch.spec.whatwg.org/#concept-cache-match-header) is found.
    ///
    /// If not, it will insert an equivalent entry
    fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool;

    /// Returns true if an entry with a
    /// [matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found
    fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool;

    /// Updates max age if an entry for
    /// [a matching method](https://fetch.spec.whatwg.org/#concept-cache-match-method) is found.
    ///
    /// If not, it will insert an equivalent entry
    fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool;
    /// Insert an entry
    fn insert(&mut self, entry: CORSCacheEntry);
}

/// A simple, vector-based CORS Cache
#[derive(Clone)]
pub struct BasicCORSCache(Vec<CORSCacheEntry>);

fn match_headers(cors_cache: &CORSCacheEntry, cors_req: &CacheRequestDetails) -> bool {
    cors_cache.origin.scheme == cors_req.origin.scheme &&
        cors_cache.origin.host() == cors_req.origin.host() &&
        cors_cache.origin.port() == cors_req.origin.port() &&
        cors_cache.url == cors_req.destination &&
        cors_cache.credentials == cors_req.credentials
}

impl BasicCORSCache {
    fn find_entry_by_header<'a>(&'a mut self, request: &CacheRequestDetails,
                                header_name: &str) -> Option<&'a mut CORSCacheEntry> {
        self.cleanup();
        let BasicCORSCache(ref mut buf) = *self;
        buf.iter_mut().find(|e| match_headers(e, request) && e.header_or_method.match_header(header_name))
    }

    fn find_entry_by_method<'a>(&'a mut self, request: &CacheRequestDetails,
                                method: Method) -> Option<&'a mut CORSCacheEntry> {
        // we can take the method from CORSRequest itself
        self.cleanup();
        let BasicCORSCache(ref mut buf) = *self;
        buf.iter_mut().find(|e| match_headers(e, request) && e.header_or_method.match_method(&method))
    }
}

impl CORSCache for BasicCORSCache {
    /// https://fetch.spec.whatwg.org/#concept-cache-clear
    #[allow(dead_code)]
    fn clear (&mut self, request: CacheRequestDetails) {
        let BasicCORSCache(buf) = self.clone();
        let new_buf: Vec<CORSCacheEntry> =
            buf.into_iter().filter(|e| e.origin == request.origin && request.destination == e.url).collect();
        *self = BasicCORSCache(new_buf);
    }

    // Remove old entries
    fn cleanup(&mut self) {
        let BasicCORSCache(buf) = self.clone();
        let now = time::now().to_timespec();
        let new_buf: Vec<CORSCacheEntry> = buf.into_iter()
                                              .filter(|e| now.sec > e.created.sec + e.max_age as i64)
                                              .collect();
        *self = BasicCORSCache(new_buf);
    }

    fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
        self.find_entry_by_header(&request, header_name).is_some()
    }

    fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool {
        match self.find_entry_by_header(&request, header_name).map(|e| e.max_age = new_max_age) {
            Some(_) => true,
            None => {
                self.insert(CORSCacheEntry::new(request.origin, request.destination, new_max_age,
                                                request.credentials,
                                                HeaderOrMethod::HeaderData(header_name.to_owned())));
                false
            }
        }
    }

    fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
        self.find_entry_by_method(&request, method).is_some()
    }

    fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool {
        match self.find_entry_by_method(&request, method.clone()).map(|e| e.max_age = new_max_age) {
            Some(_) => true,
            None => {
                self.insert(CORSCacheEntry::new(request.origin, request.destination, new_max_age,
                                                request.credentials, HeaderOrMethod::MethodData(method)));
                false
            }
        }
    }

    fn insert(&mut self, entry: CORSCacheEntry) {
        self.cleanup();
        let BasicCORSCache(ref mut buf) = *self;
        buf.push(entry);
    }
}

/// Various messages that can be sent to a CORSCacheTask
pub enum CORSCacheTaskMsg {
    Clear(CacheRequestDetails, Sender<()>),
    Cleanup(Sender<()>),
    MatchHeader(CacheRequestDetails, String, Sender<bool>),
    MatchHeaderUpdate(CacheRequestDetails, String, u32, Sender<bool>),
    MatchMethod(CacheRequestDetails, Method, Sender<bool>),
    MatchMethodUpdate(CacheRequestDetails, Method, u32, Sender<bool>),
    Insert(CORSCacheEntry, Sender<()>),
    ExitMsg
}

/// A Sender to a CORSCacheTask
///
/// This can be used as a CORS Cache.
/// The methods on this type block until they can run, and it behaves similar to a mutex
pub type CORSCacheSender = Sender<CORSCacheTaskMsg>;

impl CORSCache for CORSCacheSender {
    fn clear (&mut self, request: CacheRequestDetails) {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::Clear(request, tx));
        let _ = rx.recv();
    }

    fn cleanup(&mut self) {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::Cleanup(tx));
        let _ = rx.recv();
    }

    fn match_header(&mut self, request: CacheRequestDetails, header_name: &str) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchHeader(request, header_name.to_owned(), tx));
        rx.recv().unwrap_or(false)
    }

    fn match_header_and_update(&mut self, request: CacheRequestDetails, header_name: &str, new_max_age: u32) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchHeaderUpdate(request, header_name.to_owned(), new_max_age, tx));
        rx.recv().unwrap_or(false)
    }

    fn match_method(&mut self, request: CacheRequestDetails, method: Method) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchMethod(request, method, tx));
        rx.recv().unwrap_or(false)
    }

    fn match_method_and_update(&mut self, request: CacheRequestDetails, method: Method, new_max_age: u32) -> bool {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::MatchMethodUpdate(request, method, new_max_age, tx));
        rx.recv().unwrap_or(false)
    }

    fn insert(&mut self, entry: CORSCacheEntry) {
        let (tx, rx) = channel();
        self.send(CORSCacheTaskMsg::Insert(entry, tx));
        let _ = rx.recv();
    }
}

/// A simple task-based CORS Cache that can be sent messages
///
/// #Example
/// ```ignore
/// let task = CORSCacheTask::new();
/// let builder = TaskBuilder::new().named("XHRTask");
/// let mut sender = task.sender();
/// builder.spawn(move || { task.run() });
/// sender.insert(CORSCacheEntry::new(/* parameters here */));
/// ```
pub struct CORSCacheTask {
    receiver: Receiver<CORSCacheTaskMsg>,
    cache: BasicCORSCache,
    sender: CORSCacheSender
}

impl CORSCacheTask {
    pub fn new() -> CORSCacheTask {
        let (tx, rx) = channel();
        CORSCacheTask {
            receiver: rx,
            cache: BasicCORSCache(vec![]),
            sender: tx
        }
    }

    /// Provides a sender to the cache task
    pub fn sender(&self) -> CORSCacheSender {
        self.sender.clone()
    }

    /// Runs the cache task
    /// This blocks the current task, so it is advised
    /// to spawn a new task for this
    /// Send ExitMsg to the associated Sender to exit
    pub fn run(&mut self) {
        loop {
            match self.receiver.recv().unwrap() {
                CORSCacheTaskMsg::Clear(request, tx) => {
                    self.cache.clear(request);
                    tx.send(());
                },
                CORSCacheTaskMsg::Cleanup(tx) => {
                    self.cache.cleanup();
                    tx.send(());
                },
                CORSCacheTaskMsg::MatchHeader(request, header, tx) => {
                    tx.send(self.cache.match_header(request, &header));
                },
                CORSCacheTaskMsg::MatchHeaderUpdate(request, header, new_max_age, tx) => {
                    tx.send(self.cache.match_header_and_update(request, &header, new_max_age));
                },
                CORSCacheTaskMsg::MatchMethod(request, method, tx) => {
                    tx.send(self.cache.match_method(request, method));
                },
                CORSCacheTaskMsg::MatchMethodUpdate(request, method, new_max_age, tx) => {
                    tx.send(self.cache.match_method_and_update(request, method, new_max_age));
                },
                CORSCacheTaskMsg::Insert(entry, tx) => {
                    self.cache.insert(entry);
                    tx.send(());
                },
                CORSCacheTaskMsg::ExitMsg => break
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper(
    tcx: TyCtxt<'_>,
    module: &mut Module<impl Backend + 'static>,
) {
    use rustc::middle::lang_items::StartFnLangItem;
    use rustc::session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
        Some((def_id, entry_ty)) => (
            def_id,
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);

    fn create_entry_fn(
        tcx: TyCtxt<'_>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::SystemV,
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) = get_function_name_and_sig(tcx, instance, false);
        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let ebb = bcx.create_ebb();
            bcx.switch_to_block(ebb);
            let arg_argc = bcx.append_ebb_param(ebb, m.target_config().pointer_type());
            let arg_argv = bcx.append_ebb_param(ebb, m.target_config().pointer_type());

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap();
                let start_func_id = import_function(tcx, m, start_instance);

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(cmain_func_id, &mut ctx).unwrap();
    }
}
<commit_msg>Rustup to rustc 1.39.0-nightly (72b2abfd6 2019-08-29)<commit_after>use crate::prelude::*;

/// Create the `main` function which will initialize the rust runtime and call
/// users main function.
pub fn maybe_create_entry_wrapper(
    tcx: TyCtxt<'_>,
    module: &mut Module<impl Backend + 'static>,
) {
    use rustc::middle::lang_items::StartFnLangItem;
    use rustc::session::config::EntryFnType;

    let (main_def_id, use_start_lang_item) = match tcx.entry_fn(LOCAL_CRATE) {
        Some((def_id, entry_ty)) => (
            def_id,
            match entry_ty {
                EntryFnType::Main => true,
                EntryFnType::Start => false,
            },
        ),
        None => return,
    };

    create_entry_fn(tcx, module, main_def_id, use_start_lang_item);

    fn create_entry_fn(
        tcx: TyCtxt<'_>,
        m: &mut Module<impl Backend + 'static>,
        rust_main_def_id: DefId,
        use_start_lang_item: bool,
    ) {
        let main_ret_ty = tcx.fn_sig(rust_main_def_id).output();
        // Given that `main()` has no arguments,
        // then its return type cannot have
        // late-bound regions, since late-bound
        // regions must appear in the argument
        // listing.
        let main_ret_ty = tcx.erase_regions(&main_ret_ty.no_bound_vars().unwrap());

        let cmain_sig = Signature {
            params: vec![
                AbiParam::new(m.target_config().pointer_type()),
                AbiParam::new(m.target_config().pointer_type()),
            ],
            returns: vec![AbiParam::new(
                m.target_config().pointer_type(), /*isize*/
            )],
            call_conv: CallConv::SystemV,
        };

        let cmain_func_id = m
            .declare_function("main", Linkage::Export, &cmain_sig)
            .unwrap();

        let instance = Instance::mono(tcx, rust_main_def_id);

        let (main_name, main_sig) = get_function_name_and_sig(tcx, instance, false);
        let main_func_id = m
            .declare_function(&main_name, Linkage::Import, &main_sig)
            .unwrap();

        let mut ctx = Context::new();
        ctx.func = Function::with_name_signature(ExternalName::user(0, 0), cmain_sig.clone());
        {
            let mut func_ctx = FunctionBuilderContext::new();
            let mut bcx: FunctionBuilder = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);

            let ebb = bcx.create_ebb();
            bcx.switch_to_block(ebb);
            let arg_argc = bcx.append_ebb_param(ebb, m.target_config().pointer_type());
            let arg_argv = bcx.append_ebb_param(ebb, m.target_config().pointer_type());

            let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func);

            let call_inst = if use_start_lang_item {
                let start_def_id = tcx.require_lang_item(StartFnLangItem, None);
                let start_instance = Instance::resolve(
                    tcx,
                    ParamEnv::reveal_all(),
                    start_def_id,
                    tcx.intern_substs(&[main_ret_ty.into()]),
                )
                .unwrap();
                let start_func_id = import_function(tcx, m, start_instance);

                let main_val = bcx
                    .ins()
                    .func_addr(m.target_config().pointer_type(), main_func_ref);

                let func_ref = m.declare_func_in_func(start_func_id, &mut bcx.func);
                bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv])
            } else {
                // using user-defined start fn
                bcx.ins().call(main_func_ref, &[arg_argc, arg_argv])
            };

            let result = bcx.inst_results(call_inst)[0];
            bcx.ins().return_(&[result]);
            bcx.seal_all_blocks();
            bcx.finalize();
        }
        m.define_function(cmain_func_id, &mut ctx).unwrap();
    }
}
<|endoftext|>


<commit_before>mod page;
pub use self::page::Page;

use std::collections::BTreeMap;
use std::default::Default;
use std::env;
use std::time::Duration;

use html5ever::tokenizer::BufferQueue;
use html5ever::tokenizer::Tokenizer;
use mime;
use reqwest::header::{CONTENT_TYPE, USER_AGENT};
use reqwest::Client as HttpClient;
use reqwest::Response as HttpResponse;
use reqwest::StatusCode;
use robotparser::RobotFileParser;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use url::Url;
use url_serde::Serde;

const MAMAN_ENV: &str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    pub mime_types: Vec<mime::Mime>,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(
        redis_pool: RedisPool,
        base_url: Url,
        limit: isize,
        mime_types: Vec<mime::Mime>,
    ) -> Spider<'a> {
        let maman_env =
            env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts {
            namespace: Some(maman_env.to_string()),
        };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit,
            mime_types,
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(unknown_lints, clippy::needless_pass_by_value))]
    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in &page.urls {
            self.unvisited_urls.push(u.clone());
        }
        if let Err(err) = self.sidekiq.push(page.to_job()) {
            error!("SidekiqClient push failed: {}", err);
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref(), &self.mime_types) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref(), &self.mime_types) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser.can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for (key, value) in response.headers().iter() {
                headers.insert(
                    key.as_str().to_string(),
                    value.to_str().unwrap_or("").to_string(),
                );
            }
        }
        match response.text() {
            Ok(content) => {
                let page = Page::new(
                    page_url.clone(),
                    content.to_string(),
                    headers,
                    response.status().to_string(),
                );
                let read = Spider::read_page(page, &content);
                Some(read.sink)
            }
            _ => None,
        }
    }

    fn load_url(url: &str, mime_types: &[mime::Mime]) -> Option<HttpResponse> {
        let client = HttpClient::builder()
            .timeout(Duration::from_secs(5))
            .build()
            .expect("HttpClient failed to construct");
        match client
            .get(url)
            .header(USER_AGENT, maman_user_agent!())
            .send()
        {
            Err(_) => None,
            Ok(response) => match response.status() {
                StatusCode::OK | StatusCode::NOT_MODIFIED => {
                    if mime_types.is_empty() {
                        Some(response)
                    } else {
                        let content_type = response
                            .headers()
                            .get(CONTENT_TYPE)
                            .and_then(|value| value.to_str().ok())
                            .and_then(|value| value.parse::<mime::Mime>().ok());
                        match content_type {
                            Some(ct) => {
                                if mime_types.contains(&ct) {
                                    Some(response)
                                } else {
                                    None
                                }
                            }
                            None => None,
                        }
                    }
                }
                _ => None,
            },
        }
    }
}
<commit_msg>Rustfmt<commit_after>mod page;
pub use self::page::Page;

use std::collections::BTreeMap;
use std::default::Default;
use std::env;
use std::time::Duration;

use html5ever::tokenizer::BufferQueue;
use html5ever::tokenizer::Tokenizer;
use mime;
use reqwest::header::{CONTENT_TYPE, USER_AGENT};
use reqwest::Client as HttpClient;
use reqwest::Response as HttpResponse;
use reqwest::StatusCode;
use robotparser::RobotFileParser;
use sidekiq::Client as SidekiqClient;
use sidekiq::ClientOpts as SidekiqClientOpts;
use sidekiq::RedisPool;
use url::Url;
use url_serde::Serde;

const MAMAN_ENV: &str = "MAMAN_ENV";
const MAMAN_ENV_DEFAULT: &str = "development";

pub struct Spider<'a> {
    pub base_url: Url,
    pub visited_urls: Vec<Serde<Url>>,
    pub unvisited_urls: Vec<Serde<Url>>,
    pub env: String,
    pub limit: isize,
    pub mime_types: Vec<mime::Mime>,
    sidekiq: SidekiqClient,
    robot_parser: RobotFileParser<'a>,
}

impl<'a> Spider<'a> {
    pub fn new(
        redis_pool: RedisPool,
        base_url: Url,
        limit: isize,
        mime_types: Vec<mime::Mime>,
    ) -> Spider<'a> {
        let maman_env =
            env::var(&MAMAN_ENV.to_owned()).unwrap_or_else(|_| MAMAN_ENV_DEFAULT.to_owned());
        let robots_txt = base_url.join("/robots.txt").unwrap();
        let robot_file_parser = RobotFileParser::new(robots_txt);
        let client_opts = SidekiqClientOpts {
            namespace: Some(maman_env.to_string()),
        };
        let sidekiq = SidekiqClient::new(redis_pool, client_opts);
        Spider {
            base_url,
            visited_urls: Vec::new(),
            unvisited_urls: Vec::new(),
            sidekiq,
            env: maman_env,
            robot_parser: robot_file_parser,
            limit,
            mime_types,
        }
    }

    #[cfg_attr(
        feature = "cargo-clippy",
        allow(unknown_lints, clippy::needless_pass_by_value)
    )]
    pub fn visit_page(&mut self, page: Page) {
        self.visited_urls.push(page.url.clone());
        for u in &page.urls {
            self.unvisited_urls.push(u.clone());
        }
        if let Err(err) = self.sidekiq.push(page.to_job()) {
            error!("SidekiqClient push failed: {}", err);
        }
    }

    pub fn crawl(&mut self) {
        self.robot_parser.read();
        let base_url = self.base_url.clone();
        if let Some(response) = Spider::load_url(self.base_url.as_ref(), &self.mime_types) {
            self.visit(&base_url, response);
            while let Some(url) = self.unvisited_urls.pop() {
                if self.continue_to_crawl() {
                    if !self.visited_urls.contains(&url) {
                        if let Some(response) = Spider::load_url(url.as_ref(), &self.mime_types) {
                            self.visit(&url, response);
                        }
                    }
                } else {
                    break;
                }
            }
        }
    }

    pub fn read_page(page: Page, document: &str) -> Tokenizer<Page> {
        let mut tok = Tokenizer::new(page, Default::default());
        let mut input = BufferQueue::new();
        input.push_back(String::from(document).into());
        let _ = tok.feed(&mut input);
        tok.end();
        tok
    }

    fn visit(&mut self, page_url: &Url, response: HttpResponse) {
        if self.can_visit(page_url) {
            info!("{}", page_url);
            if let Some(page) = Spider::read_response(page_url, response) {
                self.visit_page(page);
            }
        }
    }

    fn continue_to_crawl(&self) -> bool {
        self.limit == 0 || (self.visited_urls.len() as isize) < self.limit
    }

    fn can_visit(&self, page_url: &Url) -> bool {
        self.robot_parser.can_fetch(maman_name!(), page_url.path())
    }

    fn read_response(page_url: &Url, mut response: HttpResponse) -> Option<Page> {
        let mut headers = BTreeMap::new();
        {
            for (key, value) in response.headers().iter() {
                headers.insert(
                    key.as_str().to_string(),
                    value.to_str().unwrap_or("").to_string(),
                );
            }
        }
        match response.text() {
            Ok(content) => {
                let page = Page::new(
                    page_url.clone(),
                    content.to_string(),
                    headers,
                    response.status().to_string(),
                );
                let read = Spider::read_page(page, &content);
                Some(read.sink)
            }
            _ => None,
        }
    }

    fn load_url(url: &str, mime_types: &[mime::Mime]) -> Option<HttpResponse> {
        let client = HttpClient::builder()
            .timeout(Duration::from_secs(5))
            .build()
            .expect("HttpClient failed to construct");
        match client
            .get(url)
            .header(USER_AGENT, maman_user_agent!())
            .send()
        {
            Err(_) => None,
            Ok(response) => match response.status() {
                StatusCode::OK | StatusCode::NOT_MODIFIED => {
                    if mime_types.is_empty() {
                        Some(response)
                    } else {
                        let content_type = response
                            .headers()
                            .get(CONTENT_TYPE)
                            .and_then(|value| value.to_str().ok())
                            .and_then(|value| value.parse::<mime::Mime>().ok());
                        match content_type {
                            Some(ct) => {
                                if mime_types.contains(&ct) {
                                    Some(response)
                                } else {
                                    None
                                }
                            }
                            None => None,
                        }
                    }
                }
                _ => None,
            },
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

///! Rush main

/// Rush module
mod rush
{
    use std::ptr;
    use std::io::stdio;
    use libc::funcs::posix88::unistd::execvp;
    use libc::funcs::posix88::unistd::fork;
    use libc::types::os::arch::posix88::pid_t;

    /// Wait.
    #[link(name = "c")]
    extern
    {
        fn wait (status: * mut i64) -> pid_t;
    }

    /// Print the prompt.
    fn print_prompt ()
    {
        let mut stdout = stdio::stdout ();
        let _ = stdout.write_str ("rush >> ");
        let _ = stdout.flush ();
    }

    /// Read user's input into a buffer.
    fn read_input (buffer: & mut [u8]) -> uint
    {
        let mut stdin = stdio::stdin ();
        let n = match stdin.read (buffer)
        {
            Ok (n) => n,
            Err (..) => 0,
        };
        n
    }

    /// Tokenize a buffer (split at spaces).
    fn buffer_to_tokens (n: uint, buffer: & mut [u8]) -> Vec<String>
    {
        let input_string = match String::from_utf8 (Vec::from_slice (buffer))
        {
            Ok (s) => s,
            Err (e) => fail! ("{}", e),
        };
        let tokens: Vec<&str> = input_string.as_slice().slice (0, n-1).split(' ').collect();
        let mut tokens_strings = Vec::new ();
        for s in tokens.iter ()
        {
            tokens_strings.push (String::from_str (*s));
        }
        tokens_strings
    }

    /// Run a command.
    fn run_cmd (cmd: & str, args: Vec<String>) -> pid_t
    {
        unsafe
        {
            let pid = fork ();
            if pid == 0
            {
                let cmd_c_str = cmd.to_c_str ();
                let arg_0 = cmd_c_str.clone ();
                let mut args_c : Vec<*i8> = Vec::new ();
                args_c.push (arg_0.unwrap ());
                for s in args.iter ()
                {
                    args_c.push (s.to_c_str ().unwrap ());
                }
                args_c.push (ptr::null ());
                execvp (cmd_c_str.unwrap (), args_c.as_ptr ());
            }
            pid
        }
    }

    /// Run the prompt.
    pub fn prompt ()
    {
        loop
        {
            print_prompt ();

            /* Read input. */
            let mut buffer : [u8, ..2048] = [0, ..2048];
            let n = read_input (buffer);
            let input = buffer_to_tokens (n, buffer);

            let cmd = input.as_slice ()[0].as_slice ();
            if cmd == "exit"
            {
                break;
            }

            let args = Vec::from_slice (input.as_slice ().slice (1, input.len ()));

            let pid = run_cmd (cmd, args);
            if pid == 0
            {
                break;
            }
            let mut status: i64 = 0;
            unsafe
            {
                wait (&mut status);
            }
        }
    }
}

/// Main
fn main ()
{
    rush::prompt ();
}
<commit_msg>compatibility with current rust nightlies<commit_after>extern crate libc;

///! Rush main

/// Rush module
mod rush
{
    use std::ptr;
    use std::io::stdio;
    use libc::funcs::posix88::unistd::execvp;
    use libc::funcs::posix88::unistd::fork;
    use libc::types::os::arch::posix88::pid_t;

    /// Wait.
    #[link(name = "c")]
    extern
    {
        fn wait (status: * mut i64) -> pid_t;
    }

    /// Print the prompt.
    fn print_prompt ()
    {
        let mut stdout = stdio::stdout ();
        let _ = stdout.write_str ("rush >> ");
        let _ = stdout.flush ();
    }

    /// Read user's input into a buffer.
    fn read_input (buffer: & mut [u8]) -> uint
    {
        let mut stdin = stdio::stdin ();
        let n = match stdin.read (buffer)
        {
            Ok (n) => n,
            Err (..) => 0,
        };
        n
    }

    /// Tokenize a buffer (split at spaces).
    fn buffer_to_tokens (n: uint, buffer: & mut [u8]) -> Vec<String>
    {
        let input_string = match String::from_utf8 (Vec::from_slice (buffer))
        {
            Ok (s) => s,
            Err (e) => fail! ("{}", e),
        };
        let tokens: Vec<&str> = input_string.as_slice().slice (0, n-1).split(' ').collect();
        let mut tokens_strings = Vec::new ();
        for s in tokens.iter ()
        {
            tokens_strings.push (String::from_str (*s));
        }
        tokens_strings
    }

    /// Run a command.
    fn run_cmd (cmd: & str, args: Vec<String>) -> pid_t
    {
        unsafe
        {
            let pid = fork ();
            if pid == 0
            {
                let cmd_c_str = cmd.to_c_str ();
                let arg_0 = cmd_c_str.clone ();
                let mut args_c : Vec<* const i8> = Vec::new ();
                args_c.push (arg_0.unwrap ());
                for s in args.iter ()
                {
                    args_c.push (s.to_c_str ().unwrap ());
                }
                args_c.push (ptr::null ());
                execvp (cmd_c_str.unwrap (), args_c.as_mut_ptr ());
            }
            pid
        }
    }

    /// Run the prompt.
    pub fn prompt ()
    {
        loop
        {
            print_prompt ();

            /* Read input. */
            let mut buffer : [u8, ..2048] = [0, ..2048];
            let n = read_input (buffer);
            let input = buffer_to_tokens (n, buffer);

            let cmd = input.as_slice ()[0].as_slice ();
            if cmd == "exit"
            {
                break;
            }

            let args = Vec::from_slice (input.as_slice ().slice (1, input.len ()));

            let pid = run_cmd (cmd, args);
            if pid == 0
            {
                break;
            }
            let mut status: i64 = 0;
            unsafe
            {
                wait (&mut status);
            }
        }
    }
}

/// Main
fn main ()
{
    rush::prompt ();
}
<|endoftext|>


<commit_before>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{
        layer::LayerSurface,
        popup::{PopupKind, PopupManager},
        space::{window_loc, Space, SpaceElement},
        utils::{bbox_from_surface_tree, damage_from_surface_tree},
        window::Window,
    },
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::any::TypeId;

use super::RenderZindex;

#[derive(Debug)]
pub struct RenderPopup {
    location: Point<i32, Logical>,
    popup: PopupKind,
}

impl Window {
    pub(super) fn popup_elements<R>(&self, space_id: usize) -> impl Iterator<Item = RenderPopup>
    where
        R: Renderer + ImportAll + 'static,
        R::TextureId: 'static,
        R::Error: 'static,
        R::Frame: 'static,
    {
        let loc = window_loc(self, &space_id) + self.geometry().loc;
        self.toplevel()
            .get_surface()
            .map(move |surface| {
                PopupManager::popups_for_surface(surface)
                    .ok()
                    .into_iter()
                    .flatten()
                    .map(move |(popup, location)| {
                        let offset = loc + location - popup.geometry().loc;
                        RenderPopup {
                            location: offset,
                            popup,
                        }
                    })
            })
            .into_iter()
            .flatten()
    }
}

impl LayerSurface {
    pub(super) fn popup_elements<R>(&self, space_id: usize) -> impl Iterator<Item = RenderPopup>
    where
        R: Renderer + ImportAll + 'static,
        R::TextureId: 'static,
        R::Error: 'static,
        R::Frame: 'static,
    {
        type SpaceElem<R> =
            dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;

        let loc = (self as &SpaceElem<R>).geometry(space_id).loc;
        self.get_surface()
            .map(move |surface| {
                PopupManager::popups_for_surface(surface)
                    .ok()
                    .into_iter()
                    .flatten()
                    .map(move |(popup, location)| {
                        let offset = loc + location - popup.geometry().loc;
                        RenderPopup {
                            location: offset,
                            popup,
                        }
                    })
            })
            .into_iter()
            .flatten()
    }
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for RenderPopup
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.popup
            .get_surface()
            .map(|s| s.as_ref().id() as usize)
            .unwrap_or(0)
    }

    fn type_of(&self) -> TypeId {
        TypeId::of::<RenderPopup>()
    }

    fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
        if let Some(surface) = self.popup.get_surface() {
            bbox_from_surface_tree(surface, self.location)
        } else {
            Rectangle::from_loc_and_size((0, 0), (0, 0))
        }
    }

    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        if let Some(surface) = self.popup.get_surface() {
            damage_from_surface_tree(surface, (0, 0), for_values)
        } else {
            Vec::new()
        }
    }

    #[allow(clippy::too_many_arguments)]
    fn draw(
        &self,
        _space_id: usize,
        _renderer: &mut R,
        _frame: &mut F,
        _scale: f64,
        _location: Point<i32, Logical>,
        _damage: &[Rectangle<i32, Logical>],
        _log: &slog::Logger,
    ) -> Result<(), R::Error> {
        // popups are special, we track them, but they render with their parents
        Ok(())
    }

    fn z_index(&self) -> u8 {
        RenderZindex::PopUp as u8
    }
}
<commit_msg>store parent_layer in RenderPopup for z_index implemantion<commit_after>use crate::{
    backend::renderer::{Frame, ImportAll, Renderer, Texture},
    desktop::{
        layer::LayerSurface,
        popup::{PopupKind, PopupManager},
        space::{window_loc, Space, SpaceElement},
        utils::{bbox_from_surface_tree, damage_from_surface_tree},
        window::Window,
    },
    utils::{Logical, Point, Rectangle},
    wayland::output::Output,
};
use std::any::TypeId;

use super::RenderZindex;

#[derive(Debug)]
pub struct RenderPopup {
    location: Point<i32, Logical>,
    popup: PopupKind,
    parent_layer: RenderZindex,
}

impl Window {
    pub(super) fn popup_elements<R>(&self, space_id: usize) -> impl Iterator<Item = RenderPopup>
    where
        R: Renderer + ImportAll + 'static,
        R::TextureId: 'static,
        R::Error: 'static,
        R::Frame: 'static,
    {
        let loc = window_loc(self, &space_id) + self.geometry().loc;
        self.toplevel()
            .get_surface()
            .map(move |surface| {
                PopupManager::popups_for_surface(surface)
                    .ok()
                    .into_iter()
                    .flatten()
                    .map(move |(popup, location)| {
                        let offset = loc + location - popup.geometry().loc;
                        RenderPopup {
                            location: offset,
                            popup,
                            parent_layer: RenderZindex::Shell,
                        }
                    })
            })
            .into_iter()
            .flatten()
    }
}

impl LayerSurface {
    pub(super) fn popup_elements<R>(&self, space_id: usize) -> impl Iterator<Item = RenderPopup>
    where
        R: Renderer + ImportAll + 'static,
        R::TextureId: 'static,
        R::Error: 'static,
        R::Frame: 'static,
    {
        type SpaceElem<R> =
            dyn SpaceElement<R, <R as Renderer>::Frame, <R as Renderer>::Error, <R as Renderer>::TextureId>;

        let loc = (self as &SpaceElem<R>).geometry(space_id).loc;
        self.get_surface()
            .map(move |surface| {
                PopupManager::popups_for_surface(surface)
                    .ok()
                    .into_iter()
                    .flatten()
                    .map(move |(popup, location)| {
                        let offset = loc + location - popup.geometry().loc;
                        RenderPopup {
                            location: offset,
                            popup,
                            parent_layer: RenderZindex::Overlay,
                        }
                    })
            })
            .into_iter()
            .flatten()
    }
}

impl<R, F, E, T> SpaceElement<R, F, E, T> for RenderPopup
where
    R: Renderer<Error = E, TextureId = T, Frame = F> + ImportAll,
    F: Frame<Error = E, TextureId = T>,
    E: std::error::Error,
    T: Texture + 'static,
{
    fn id(&self) -> usize {
        self.popup
            .get_surface()
            .map(|s| s.as_ref().id() as usize)
            .unwrap_or(0)
    }

    fn type_of(&self) -> TypeId {
        TypeId::of::<RenderPopup>()
    }

    fn geometry(&self, _space_id: usize) -> Rectangle<i32, Logical> {
        if let Some(surface) = self.popup.get_surface() {
            bbox_from_surface_tree(surface, self.location)
        } else {
            Rectangle::from_loc_and_size((0, 0), (0, 0))
        }
    }

    fn accumulated_damage(&self, for_values: Option<(&Space, &Output)>) -> Vec<Rectangle<i32, Logical>> {
        if let Some(surface) = self.popup.get_surface() {
            damage_from_surface_tree(surface, (0, 0), for_values)
        } else {
            Vec::new()
        }
    }

    #[allow(clippy::too_many_arguments)]
    fn draw(
        &self,
        _space_id: usize,
        _renderer: &mut R,
        _frame: &mut F,
        _scale: f64,
        _location: Point<i32, Logical>,
        _damage: &[Rectangle<i32, Logical>],
        _log: &slog::Logger,
    ) -> Result<(), R::Error> {
        // popups are special, we track them, but they render with their parents
        Ok(())
    }

    fn z_index(&self) -> u8 {
        match self.parent_layer {
            RenderZindex::Shell => RenderZindex::PopUpsShell as u8,
            RenderZindex::Overlay => RenderZindex::PopUpsOverlay as u8,
            _ => 0, //Maybe better panic here? Or return u8::MAX?
        }
    }
}
<|endoftext|>