<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, build_schema, check_project, commit_project};
use crate::compiler_state::{CompilerState, ProjectName};
use crate::config::Config;
use crate::errors::{BuildProjectError, Error, Result};
use crate::graphql_asts::GraphQLAsts;
use crate::{
    artifact_map::ArtifactMap,
    watchman::{source_for_location, FileSource},
};
use common::{PerfLogEvent, PerfLogger};
use graphql_ir::ValidationError;
use log::{error, info};
use rayon::prelude::*;
use schema::Schema;
use std::fmt::Write;
use std::{collections::HashMap, sync::Arc};

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Config,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Config, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config,
            perf_logger,
        }
    }

    pub async fn compile(&self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let mut compiler_state = file_source
            .query(&setup_event, self.perf_logger.as_ref())
            .await?;
        self.build_projects(&mut compiler_state, &setup_event)
            .await?;

        self.perf_logger.complete_event(setup_event);

        Ok(compiler_state)
    }

    pub fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> HashMap<ProjectName, Arc<Schema>> {
        let timer = setup_event.start("build_schemas");
        let mut schemas = HashMap::new();
        self.config.for_each_project(|project_config| {
            let schema = build_schema(compiler_state, project_config);
            schemas.insert(project_config.name, Arc::new(schema));
        });
        setup_event.stop(timer);
        schemas
    }

    pub async fn watch_with_callback<F>(&self, mut callback: F) -> Result<()>
    where
        F: FnMut(Result<()>),
    {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;
        let schemas = self.build_schemas(&compiler_state, &setup_event);
        callback(
            self.check_projects(&mut compiler_state, &schemas, &setup_event)
                .await,
        );

        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_check_event =
                    self.perf_logger.create_event("incremental_check_event");
                let incremental_check_time =
                    incremental_check_event.start("incremental_check_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file
                let had_new_changes = compiler_state.add_pending_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_check_event,
                    self.perf_logger.as_ref(),
                )?;
                if had_new_changes {
                    // Clear out existing errors
                    callback(Ok(()));
                    // Report any new errors
                    callback(
                        self.check_projects(
                            &mut compiler_state,
                            &schemas,
                            &incremental_check_event,
                        )
                        .await,
                    );
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_check_event.stop(incremental_check_time);
                self.perf_logger.complete_event(incremental_check_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    pub async fn watch(&self) -> Result<()> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;

        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;

        if let Err(errors) = self.build_projects(&mut compiler_state, &setup_event).await {
            // TODO correctly print errors
            error!("Errors: {:#?}", errors)
        }
        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file

                info!("\n\n[watch-mode] Change detected");
                let had_new_changes = compiler_state.add_pending_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_build_event,
                    self.perf_logger.as_ref(),
                )?;

                if had_new_changes {
                    if let Err(errors) = self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                    {
                        // TODO correctly print errors
                        error!("Errors: {:#?}", errors)
                    }
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_build_event.stop(incremental_build_time);
                self.perf_logger.complete_event(incremental_build_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    async fn check_projects(
        &self,
        compiler_state: &mut CompilerState,
        schemas: &HashMap<ProjectName, Arc<Schema>>,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let graphql_asts = setup_event.time("parse_sources_time", || {
            GraphQLAsts::from_graphql_sources(&compiler_state.graphql_sources)
        })?;

        let mut build_project_errors = vec![];

        match self.config.only_project {
            Some(project_key) => {
                let project_config =
                    self.config.projects.get(&project_key).unwrap_or_else(|| {
                        panic!("Expected the project {} to exist", &project_key)
                    });
                let schema = Arc::clone(schemas.get(&project_config.name).unwrap());
                check_project(
                    project_config,
                    compiler_state,
                    &graphql_asts,
                    schema,
                    Arc::clone(&self.perf_logger),
                )
                .map_err(|err| {
                    build_project_errors.push(err);
                })
                .ok();
            }
            None => {
                for project_config in self.config.projects.values() {
                    if compiler_state.project_has_pending_changes(project_config.name) {
                        let schema = Arc::clone(schemas.get(&project_config.name).unwrap());
                        // TODO: consider running all projects in parallel
                        check_project(
                            project_config,
                            compiler_state,
                            &graphql_asts,
                            schema,
                            Arc::clone(&self.perf_logger),
                        )
                        .map_err(|err| {
                            build_project_errors.push(err);
                        })
                        .ok();
                    }
                }
            }
        }

        if build_project_errors.is_empty() {
            Ok(())
        } else {
            Err(Error::BuildProjectsErrors {
                errors: build_project_errors,
            })
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let graphql_asts = setup_event.time("parse_sources_time", || {
            GraphQLAsts::from_graphql_sources(&compiler_state.graphql_sources)
        })?;

        let next_artifacts: ArtifactMap = Default::default();

        let build_results: Vec<_> = if let Some(only_project) = self.config.only_project {
            let project_config = self
                .config
                .projects
                .get(&only_project)
                .unwrap_or_else(|| panic!("Expected the project {} to exist", &only_project));
            vec![build_project(
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&self.perf_logger),
            )]
        } else {
            self.config
                .projects
                .par_iter()
                .filter_map(|(_name, project_config)| {
                    if compiler_state.project_has_pending_changes(project_config.name) {
                        Some(build_project(
                            project_config,
                            compiler_state,
                            &graphql_asts,
                            Arc::clone(&self.perf_logger),
                        ))
                    } else {
                        None
                    }
                })
                .collect()
        };
        let mut results = Vec::new();
        let mut errors = Vec::new();
        for result in build_results {
            match result {
                Ok(result) => results.push(result),
                Err(error) => errors.push(error),
            }
        }

        if errors.is_empty() {
            for result in results {
                let (project_name, schema, programs, artifacts) = result;
                let project_config =
                    self.config.projects.get(&project_name).unwrap_or_else(|| {
                        panic!("Expected the project {} to exist", project_name)
                    });
                let result = commit_project(
                    &self.config,
                    project_config,
                    Arc::clone(&self.perf_logger),
                    &schema,
                    programs,
                    artifacts,
                )
                .await;
                match result {
                    Ok(_) => {}
                    Err(error) => {
                        errors.push(error);
                        break;
                    }
                }
            }
        }

        if errors.is_empty() {
            compiler_state.complete_compilation(next_artifacts);
            Ok(())
        } else {
            for error in &errors {
                self.print_project_error(error);
            }
            Err(Error::BuildProjectsErrors { errors })
        }
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        if let BuildProjectError::ValidationErrors { errors } = error {
            for ValidationError { message, locations } in errors {
                let locations_and_source: Vec<_> = locations
                    .iter()
                    .map(|&location| {
                        let source = source_for_location(&self.config.root_dir, location);
                        (location, source)
                    })
                    .collect();
                let mut error_message = format!("{}", message);
                for (location, source) in locations_and_source {
                    if let Some(source) = source {
                        write!(
                            error_message,
                            "\n{}",
                            location.print(&source.text, source.line_index, source.column_index)
                        )
                        .unwrap();
                    } else {
                        write!(error_message, "\n{:?}", location).unwrap();
                    }
                }
                error!("{}", error_message);
            }
        };
    }
}
<commit_msg>Commit projects concurrently<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::build_project::{build_project, build_schema, check_project, commit_project};
use crate::compiler_state::{CompilerState, ProjectName};
use crate::config::Config;
use crate::errors::{BuildProjectError, Error, Result};
use crate::graphql_asts::GraphQLAsts;
use crate::{
    artifact_map::ArtifactMap,
    watchman::{source_for_location, FileSource},
};
use common::{PerfLogEvent, PerfLogger};
use graphql_ir::ValidationError;
use log::{error, info};
use rayon::prelude::*;
use schema::Schema;
use std::fmt::Write;
use std::{collections::HashMap, sync::Arc};

pub struct Compiler<TPerfLogger>
where
    TPerfLogger: PerfLogger + 'static,
{
    config: Config,
    perf_logger: Arc<TPerfLogger>,
}

impl<TPerfLogger: PerfLogger> Compiler<TPerfLogger> {
    pub fn new(config: Config, perf_logger: Arc<TPerfLogger>) -> Self {
        Self {
            config,
            perf_logger,
        }
    }

    pub async fn compile(&self) -> Result<CompilerState> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let mut compiler_state = file_source
            .query(&setup_event, self.perf_logger.as_ref())
            .await?;
        self.build_projects(&mut compiler_state, &setup_event)
            .await?;

        self.perf_logger.complete_event(setup_event);

        Ok(compiler_state)
    }

    pub fn build_schemas(
        &self,
        compiler_state: &CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> HashMap<ProjectName, Arc<Schema>> {
        let timer = setup_event.start("build_schemas");
        let mut schemas = HashMap::new();
        self.config.for_each_project(|project_config| {
            let schema = build_schema(compiler_state, project_config);
            schemas.insert(project_config.name, Arc::new(schema));
        });
        setup_event.stop(timer);
        schemas
    }

    pub async fn watch_with_callback<F>(&self, mut callback: F) -> Result<()>
    where
        F: FnMut(Result<()>),
    {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;
        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;
        let schemas = self.build_schemas(&compiler_state, &setup_event);
        callback(
            self.check_projects(&mut compiler_state, &schemas, &setup_event)
                .await,
        );

        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_check_event =
                    self.perf_logger.create_event("incremental_check_event");
                let incremental_check_time =
                    incremental_check_event.start("incremental_check_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file
                let had_new_changes = compiler_state.add_pending_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_check_event,
                    self.perf_logger.as_ref(),
                )?;
                if had_new_changes {
                    // Clear out existing errors
                    callback(Ok(()));
                    // Report any new errors
                    callback(
                        self.check_projects(
                            &mut compiler_state,
                            &schemas,
                            &incremental_check_event,
                        )
                        .await,
                    );
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_check_event.stop(incremental_check_time);
                self.perf_logger.complete_event(incremental_check_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    pub async fn watch(&self) -> Result<()> {
        let setup_event = self.perf_logger.create_event("compiler_setup");

        let file_source = FileSource::connect(&self.config, &setup_event).await?;

        let (mut compiler_state, mut subscription) = file_source
            .subscribe(&setup_event, self.perf_logger.as_ref())
            .await?;

        if let Err(errors) = self.build_projects(&mut compiler_state, &setup_event).await {
            // TODO correctly print errors
            error!("Errors: {:#?}", errors)
        }
        self.perf_logger.complete_event(setup_event);

        loop {
            if let Some(file_source_changes) = subscription.next_change().await? {
                let incremental_build_event =
                    self.perf_logger.create_event("incremental_build_event");
                let incremental_build_time =
                    incremental_build_event.start("incremental_build_time");

                // TODO Single change to file in VSCode sometimes produces
                // 2 watchman change events for the same file

                info!("\n\n[watch-mode] Change detected");
                let had_new_changes = compiler_state.add_pending_file_source_changes(
                    &self.config,
                    &file_source_changes,
                    &incremental_build_event,
                    self.perf_logger.as_ref(),
                )?;

                if had_new_changes {
                    if let Err(errors) = self
                        .build_projects(&mut compiler_state, &incremental_build_event)
                        .await
                    {
                        // TODO correctly print errors
                        error!("Errors: {:#?}", errors)
                    }
                } else {
                    info!("[watch-mode] No re-compilation required");
                }
                incremental_build_event.stop(incremental_build_time);
                self.perf_logger.complete_event(incremental_build_event);
                // We probably don't want the messages queue to grow indefinitely
                // and we need to flush then, as the check/build is completed
                self.perf_logger.flush();
            }
        }
    }

    async fn check_projects(
        &self,
        compiler_state: &mut CompilerState,
        schemas: &HashMap<ProjectName, Arc<Schema>>,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let graphql_asts = setup_event.time("parse_sources_time", || {
            GraphQLAsts::from_graphql_sources(&compiler_state.graphql_sources)
        })?;

        let mut build_project_errors = vec![];

        match self.config.only_project {
            Some(project_key) => {
                let project_config =
                    self.config.projects.get(&project_key).unwrap_or_else(|| {
                        panic!("Expected the project {} to exist", &project_key)
                    });
                let schema = Arc::clone(schemas.get(&project_config.name).unwrap());
                check_project(
                    project_config,
                    compiler_state,
                    &graphql_asts,
                    schema,
                    Arc::clone(&self.perf_logger),
                )
                .map_err(|err| {
                    build_project_errors.push(err);
                })
                .ok();
            }
            None => {
                for project_config in self.config.projects.values() {
                    if compiler_state.project_has_pending_changes(project_config.name) {
                        let schema = Arc::clone(schemas.get(&project_config.name).unwrap());
                        // TODO: consider running all projects in parallel
                        check_project(
                            project_config,
                            compiler_state,
                            &graphql_asts,
                            schema,
                            Arc::clone(&self.perf_logger),
                        )
                        .map_err(|err| {
                            build_project_errors.push(err);
                        })
                        .ok();
                    }
                }
            }
        }

        if build_project_errors.is_empty() {
            Ok(())
        } else {
            Err(Error::BuildProjectsErrors {
                errors: build_project_errors,
            })
        }
    }

    async fn build_projects(
        &self,
        compiler_state: &mut CompilerState,
        setup_event: &impl PerfLogEvent,
    ) -> Result<()> {
        let graphql_asts = setup_event.time("parse_sources_time", || {
            GraphQLAsts::from_graphql_sources(&compiler_state.graphql_sources)
        })?;

        let next_artifacts: ArtifactMap = Default::default();

        let build_results: Vec<_> = if let Some(only_project) = self.config.only_project {
            let project_config = self
                .config
                .projects
                .get(&only_project)
                .unwrap_or_else(|| panic!("Expected the project {} to exist", &only_project));
            vec![build_project(
                project_config,
                compiler_state,
                &graphql_asts,
                Arc::clone(&self.perf_logger),
            )]
        } else {
            self.config
                .projects
                .par_iter()
                .filter_map(|(_name, project_config)| {
                    if compiler_state.project_has_pending_changes(project_config.name) {
                        Some(build_project(
                            project_config,
                            compiler_state,
                            &graphql_asts,
                            Arc::clone(&self.perf_logger),
                        ))
                    } else {
                        None
                    }
                })
                .collect()
        };
        let mut results = Vec::new();
        let mut errors = Vec::new();
        for result in build_results {
            match result {
                Ok(result) => results.push(result),
                Err(error) => errors.push(error),
            }
        }

        let errors = if errors.is_empty() {
            let mut handles = Vec::new();
            let errors_mutex = Arc::new(std::sync::Mutex::new(errors));
            for result in results {
                let errors_mutex = Arc::clone(&errors_mutex);
                handles.push(async move {
                    let (project_name, schema, programs, artifacts) = result;
                    let project_config =
                        self.config.projects.get(&project_name).unwrap_or_else(|| {
                            panic!("Expected the project {} to exist", project_name)
                        });
                    let result = commit_project(
                        &self.config,
                        project_config,
                        Arc::clone(&self.perf_logger),
                        &schema,
                        programs,
                        artifacts,
                    )
                    .await;
                    match result {
                        Ok(_) => {}
                        Err(error) => {
                            let mut errors = errors_mutex.lock().unwrap();
                            errors.push(error);
                        }
                    }
                })
            }
            futures::future::join_all(handles).await;
            Arc::try_unwrap(errors_mutex).unwrap().into_inner().unwrap()
        } else {
            errors
        };

        if errors.is_empty() {
            compiler_state.complete_compilation(next_artifacts);
            Ok(())
        } else {
            for error in &errors {
                self.print_project_error(error);
            }
            Err(Error::BuildProjectsErrors { errors })
        }
    }

    fn print_project_error(&self, error: &BuildProjectError) {
        if let BuildProjectError::ValidationErrors { errors } = error {
            for ValidationError { message, locations } in errors {
                let locations_and_source: Vec<_> = locations
                    .iter()
                    .map(|&location| {
                        let source = source_for_location(&self.config.root_dir, location);
                        (location, source)
                    })
                    .collect();
                let mut error_message = format!("{}", message);
                for (location, source) in locations_and_source {
                    if let Some(source) = source {
                        write!(
                            error_message,
                            "\n{}",
                            location.print(&source.text, source.line_index, source.column_index)
                        )
                        .unwrap();
                    } else {
                        write!(error_message, "\n{:?}", location).unwrap();
                    }
                }
                error!("{}", error_message);
            }
        };
    }
}
<|endoftext|>


<commit_before>use crate::spec::{FramePointer, RelroLevel, TargetOptions};

pub fn opts() -> TargetOptions {
    TargetOptions {
        os: "freebsd".to_string(),
        dynamic_linking: true,
        executables: true,
        families: vec!["unix".to_string()],
        has_rpath: true,
        position_independent_executables: true,
        frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
        relro_level: RelroLevel::Full,
        abi_return_struct_as_int: true,
        dwarf_version: Some(2),
        ..Default::default()
    }
}
<commit_msg>Rollup merge of #87457 - devnexen:fbsd_remove_workaround, r=petrochenkov<commit_after>use crate::spec::{RelroLevel, TargetOptions};

pub fn opts() -> TargetOptions {
    TargetOptions {
        os: "freebsd".to_string(),
        dynamic_linking: true,
        executables: true,
        families: vec!["unix".to_string()],
        has_rpath: true,
        position_independent_executables: true,
        relro_level: RelroLevel::Full,
        abi_return_struct_as_int: true,
        dwarf_version: Some(2),
        ..Default::default()
    }
}
<|endoftext|>


<commit_before>//! Layout handling

use rustwlc::handle::{WlcView, WlcOutput};

#[derive(PartialEq, Clone, Copy)]
pub enum ContainerType {
    Root,        /* Root container, only one exists */
    Output,      /* Output, like a monitor or head */
    Workspace,   /* A workspace */
    View         /* A view (aka a window) */
}

enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Like i3, everything (workspaces, containers, views) are containable.
pub trait Containable {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable>;

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Box<Containable>>;

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType;

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool;

    /// Removes this container and all of its children
    fn remove_container(self);

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibilty: bool);

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64);

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64);

    /// Finds a parent container with the given type
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable>;
}

/// View specific functions
pub trait Viewable {
    /// Determines if the view is full screen
    fn is_fullscreen(&self) -> bool;

    /// Figures out if the view is focused
    fn is_active(&self) -> bool;

    /// Returns true if this view is a parent is an ancestor of the child
    fn is_parent_of<T: Containable>(&self, child: T) -> bool;

    /// Returns true if this view is a child is an decedent of the parent
    fn is_child_of<T: Containable>(&self, parent: T) -> bool;

    /// Gets the active workspace of the view
    fn active_workspace<T: Containable>(&self) -> T;
}

struct Container<T: Containable> {
    handle: Option<WlcOutput>,

    parent: Box<T>,
    children: Vec<Box<T>>,
    type_: ContainerType,
    layout: Layout,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl<C: Containable> Containable for Container<C> {

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable> {
        match self.type_ {
            ContainerType::Root => None,
            _ => Some(&*self.parent as &Containable),
        }
    }
    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Box<Containable>> {
        unimplemented!();
    }

    fn get_type(&self) -> ContainerType {
        self.type_
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(self) {
        for child in self.children {
            child.remove_container();
        }
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibilty: bool) {
        self.visible = visibilty
    }

    /// Gets the X (width) and Y (height) dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Finds a parent container with the given type, if there is any
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable> {
        let mut container = self.get_parent();
        while container.is_some() && container.unwrap().get_type() != type_ {
            container = container.unwrap().get_parent();
        }
        container
    }
}

struct View {
    handle: Option<WlcView>,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}
<commit_msg>Switched from Box to Rc for children<commit_after>//! Layout handling

use rustwlc::handle::{WlcView, WlcOutput};
use std::rc::{Rc, Weak};

#[derive(PartialEq, Clone, Copy)]
pub enum ContainerType {
    Root,        /* Root container, only one exists */
    Output,      /* Output, like a monitor or head */
    Workspace,   /* A workspace */
    View         /* A view (aka a window) */
}

enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

/// Like i3, everything (workspaces, containers, views) are containable.
pub trait Containable {
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable>;

    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<&Containable>>;

    /// Gets the type of the container
    fn get_type(&self) -> ContainerType;

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool;

    /// Removes this container and all of its children
    fn remove_container(self);

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibilty: bool);

    /// Gets the X and Y dimensions of the container
    fn get_dimensions(&self) -> (u64, u64);

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64);

    /// Finds a parent container with the given type
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable>;
}

/// View specific functions
pub trait Viewable {
    /// Determines if the view is full screen
    fn is_fullscreen(&self) -> bool;

    /// Figures out if the view is focused
    fn is_active(&self) -> bool;

    /// Returns true if this view is a parent is an ancestor of the child
    fn is_parent_of<T: Containable>(&self, child: T) -> bool;

    /// Returns true if this view is a child is an decedent of the parent
    fn is_child_of<T: Containable>(&self, parent: T) -> bool;

    /// Gets the active workspace of the view
    fn active_workspace<T: Containable>(&self) -> T;
}

struct Container<T: Containable> {
    handle: Option<WlcOutput>,

    parent: Box<T>,
    children: Vec<Rc<T>>,
    type_: ContainerType,
    layout: Layout,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

impl<C: Containable> Containable for Container<C> {

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    fn get_parent(&self) -> Option<&Containable> {
        match self.type_ {
            ContainerType::Root => None,
            _ => Some(&*self.parent as &Containable),
        }
    }
    /// Gets the children of this container.
    ///
    /// Views never have children
    fn get_children(&self) -> Vec<Weak<&Containable>> {
        unimplemented!();
    }

    fn get_type(&self) -> ContainerType {
        self.type_
    }

    /// Returns true if this container is focused.
    fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes this container and all of its children
    fn remove_container(self) {
        unimplemented!();
    }

    /// Sets this container (and everything in it) to given visibility
    fn set_visibility(&mut self, visibilty: bool) {
        self.visible = visibilty
    }

    /// Gets the X (width) and Y (height) dimensions of the container
    fn get_dimensions(&self) -> (u64, u64) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Finds a parent container with the given type, if there is any
    fn get_parent_by_type(&self, type_: ContainerType) -> Option<&Containable> {
        let mut container = self.get_parent();
        while container.is_some() && container.unwrap().get_type() != type_ {
            container = container.unwrap().get_parent();
        }
        container
    }
}

struct View {
    handle: Option<WlcView>,

    width: u64,
    height: u64,

    x: i64,
    y: i64,

    visible: bool,
    is_focused: bool,
    is_floating: bool,
}
<|endoftext|>


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

use syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use utils::{match_def_path, unsafe_context};

declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects");

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptTask`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass {
    in_new_function: bool
}

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass {
            in_new_function: true
        }
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::TyStruct(did, _) |
            ty::TyEnum(did, _) => {
                if cx.tcx.has_attr(did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did, &["core", "cell", "Ref"])
                        || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
                        // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
                        // since it will be rooted elsewhere
                    false
                } else {
                    true
                }
            },
            ty::TyBox(..) if in_new_function => false, // box in new() is okay
            ty::TyRef(..) => false, // don't recurse down &ptrs
            ty::TyRawPtr(..) => false, // don't recurse down *ptrs
            _ => true
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self,
                        cx: &Context,
                        def: &ast::StructDef,
                        _i: ast::Ident,
                        _gen: &ast::Generics,
                        id: ast::NodeId) {
        let item = match cx.tcx.map.get(id) {
            ast_map::Node::NodeItem(item) => item,
            _ => cx.tcx.map.expect_item(cx.tcx.map.get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        ast_ty_to_prim_ty(cx.tcx, &*ty.ty).map(|t| {
                            if is_unrooted_ty(cx, t, false) {
                                cx.span_lint(UNROOTED_MUST_ROOT, ty.ty.span,
                                             "Type must be rooted, use #[must_root] on \
                                              the enum definition to propagate")
                            }
                        });
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _, _, _) |
            visit::FkMethod(i, _, _) if i.name.as_str() == "new"
                                        || i.name.as_str() == "new_inherited"
                                        || i.name.as_str() == "new_initialized" => {
                self.in_new_function = true;
                return;
            },
            visit::FkItemFn(_, _, style, _, _, _) => match style {
                ast::Unsafety::Unsafe => return,
                _ => ()
            },
            _ => ()
        }
        self.in_new_function = false;

        if unsafe_context(&cx.tcx.map, id) {
            return;
        }

        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    ast_ty_to_prim_ty(cx.tcx, &*arg.ty).map(|t| {
                        if is_unrooted_ty(cx, t, false) {
                            cx.span_lint(UNROOTED_MUST_ROOT, arg.ty.span, "Type must be rooted")
                        }
                    });
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    /// Trait casts from #[must_root] types are not allowed
    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        fn require_rooted(cx: &Context, in_new_function: bool, subexpr: &ast::Expr) {
            let ty = cx.tcx.expr_ty(&*subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(UNROOTED_MUST_ROOT,
                             subexpr.span,
                             &format!("Expression of type {:?} must be rooted", ty))
            }
        };

        match expr.node {
            ast::ExprCast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            }
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        match s.node {
            ast::StmtDecl(_, id) |
            ast::StmtExpr(_, id) |
            ast::StmtSemi(_, id) if unsafe_context(&cx.tcx.map, id) => {
                return
            },
            _ => ()
        };

        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant`
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _, _) |
                // For loops allow you to bind a return value locally
                ast::ExprForLoop(_, ref e, _, _) => &**e,
                // XXXManishearth look into `if let` once it lands in our rustc
                _ => return
            },
            _ => return
        };

        let ty = cx.tcx.expr_ty(&*expr);
        if is_unrooted_ty(cx, ty, self.in_new_function) {
            cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                     &format!("Expression of type {:?} must be rooted", ty))
        }
    }
}
<commit_msg>Auto merge of #6945 - Manishearth:fixedme, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::{ast, codemap, visit};
use syntax::attr::AttrMetaMethods;
use rustc::ast_map;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::ty;
use rustc::middle::astconv_util::ast_ty_to_prim_ty;
use utils::{match_def_path, unsafe_context};

declare_lint!(UNROOTED_MUST_ROOT, Deny,
              "Warn and report usage of unrooted jsmanaged objects");

/// Lint for ensuring safe usage of unrooted pointers
///
/// This lint (disable with `-A unrooted-must-root`/`#[allow(unrooted_must_root)]`) ensures that `#[must_root]`
/// values are used correctly.
///
/// "Incorrect" usage includes:
///
///  - Not being used in a struct/enum field which is not `#[must_root]` itself
///  - Not being used as an argument to a function (Except onces named `new` and `new_inherited`)
///  - Not being bound locally in a `let` statement, assignment, `for` loop, or `match` statement.
///
/// This helps catch most situations where pointers like `JS<T>` are used in a way that they can be invalidated by a
/// GC pass.
///
/// Structs which have their own mechanism of rooting their unrooted contents (e.g. `ScriptTask`)
/// can be marked as `#[allow(unrooted_must_root)]`. Smart pointers which root their interior type
/// can be marked as `#[allow_unrooted_interior]`
pub struct UnrootedPass {
    in_new_function: bool
}

impl UnrootedPass {
    pub fn new() -> UnrootedPass {
        UnrootedPass {
            in_new_function: true
        }
    }
}

/// Checks if a type is unrooted or contains any owned unrooted types
fn is_unrooted_ty(cx: &Context, ty: &ty::TyS, in_new_function: bool) -> bool {
    let mut ret = false;
    ty.maybe_walk(|t| {
        match t.sty {
            ty::TyStruct(did, _) |
            ty::TyEnum(did, _) => {
                if cx.tcx.has_attr(did, "must_root") {
                    ret = true;
                    false
                } else if cx.tcx.has_attr(did, "allow_unrooted_interior") {
                    false
                } else if match_def_path(cx, did, &["core", "cell", "Ref"])
                        || match_def_path(cx, did, &["core", "cell", "RefMut"]) {
                        // Ref and RefMut are borrowed pointers, okay to hold unrooted stuff
                        // since it will be rooted elsewhere
                    false
                } else {
                    true
                }
            },
            ty::TyBox(..) if in_new_function => false, // box in new() is okay
            ty::TyRef(..) => false, // don't recurse down &ptrs
            ty::TyRawPtr(..) => false, // don't recurse down *ptrs
            _ => true
        }
    });
    ret
}

impl LintPass for UnrootedPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNROOTED_MUST_ROOT)
    }
    /// All structs containing #[must_root] types must be #[must_root] themselves
    fn check_struct_def(&mut self,
                        cx: &Context,
                        def: &ast::StructDef,
                        _i: ast::Ident,
                        _gen: &ast::Generics,
                        id: ast::NodeId) {
        let item = match cx.tcx.map.get(id) {
            ast_map::Node::NodeItem(item) => item,
            _ => cx.tcx.map.expect_item(cx.tcx.map.get_parent(id)),
        };
        if item.attrs.iter().all(|a| !a.check_name("must_root")) {
            for ref field in def.fields.iter() {
                if is_unrooted_ty(cx, cx.tcx.node_id_to_type(field.node.id), false) {
                    cx.span_lint(UNROOTED_MUST_ROOT, field.span,
                                 "Type must be rooted, use #[must_root] on the struct definition to propagate")
                }
            }
        }
    }
    /// All enums containing #[must_root] types must be #[must_root] themselves
    fn check_variant(&mut self, cx: &Context, var: &ast::Variant, _gen: &ast::Generics) {
        let ref map = cx.tcx.map;
        if map.expect_item(map.get_parent(var.node.id)).attrs.iter().all(|a| !a.check_name("must_root")) {
            match var.node.kind {
                ast::TupleVariantKind(ref vec) => {
                    for ty in vec.iter() {
                        ast_ty_to_prim_ty(cx.tcx, &*ty.ty).map(|t| {
                            if is_unrooted_ty(cx, t, false) {
                                cx.span_lint(UNROOTED_MUST_ROOT, ty.ty.span,
                                             "Type must be rooted, use #[must_root] on \
                                              the enum definition to propagate")
                            }
                        });
                    }
                }
                _ => () // Struct variants already caught by check_struct_def
            }
        }
    }
    /// Function arguments that are #[must_root] types are not allowed
    fn check_fn(&mut self, cx: &Context, kind: visit::FnKind, decl: &ast::FnDecl,
                block: &ast::Block, _span: codemap::Span, id: ast::NodeId) {
        match kind {
            visit::FkItemFn(i, _, _, _, _, _) |
            visit::FkMethod(i, _, _) if i.name.as_str() == "new"
                                        || i.name.as_str() == "new_inherited"
                                        || i.name.as_str() == "new_initialized" => {
                self.in_new_function = true;
                return;
            },
            visit::FkItemFn(_, _, style, _, _, _) => match style {
                ast::Unsafety::Unsafe => return,
                _ => ()
            },
            _ => ()
        }
        self.in_new_function = false;

        if unsafe_context(&cx.tcx.map, id) {
            return;
        }

        match block.rules {
            ast::DefaultBlock => {
                for arg in decl.inputs.iter() {
                    ast_ty_to_prim_ty(cx.tcx, &*arg.ty).map(|t| {
                        if is_unrooted_ty(cx, t, false) {
                            cx.span_lint(UNROOTED_MUST_ROOT, arg.ty.span, "Type must be rooted")
                        }
                    });
                }
            }
            _ => () // fn is `unsafe`
        }
    }

    /// Trait casts from #[must_root] types are not allowed
    fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
        fn require_rooted(cx: &Context, in_new_function: bool, subexpr: &ast::Expr) {
            let ty = cx.tcx.expr_ty(&*subexpr);
            if is_unrooted_ty(cx, ty, in_new_function) {
                cx.span_lint(UNROOTED_MUST_ROOT,
                             subexpr.span,
                             &format!("Expression of type {:?} must be rooted", ty))
            }
        };

        match expr.node {
            ast::ExprCast(ref subexpr, _) => require_rooted(cx, self.in_new_function, &*subexpr),
            _ => {
                // TODO(pcwalton): Check generics with a whitelist of allowed generics.
            }
        }
    }

    // Partially copied from rustc::middle::lint::builtin
    // Catches `let` statements and assignments which store a #[must_root] value
    // Expressions which return out of blocks eventually end up in a `let` or assignment
    // statement or a function return (which will be caught when it is used elsewhere)
    fn check_stmt(&mut self, cx: &Context, s: &ast::Stmt) {
        match s.node {
            ast::StmtDecl(_, id) |
            ast::StmtExpr(_, id) |
            ast::StmtSemi(_, id) if unsafe_context(&cx.tcx.map, id) => {
                return
            },
            _ => ()
        };

        let expr = match s.node {
            // Catch a `let` binding
            ast::StmtDecl(ref decl, _) => match decl.node {
                ast::DeclLocal(ref loc) => match loc.init {
                    Some(ref e) => &**e,
                    _ => return
                },
                _ => return
            },
            ast::StmtExpr(ref expr, _) => match expr.node {
                // This catches deferred `let` statements
                ast::ExprAssign(_, ref e) |
                // Match statements allow you to bind onto the variable later in an arm
                // We need not check arms individually since enum/struct fields are already
                // linted in `check_struct_def` and `check_variant`
                // (so there is no way of destructuring out a `#[must_root]` field)
                ast::ExprMatch(ref e, _, _) => &**e,
                // These are able to bind local variables, but are desugared into
                // loops and matches pre-lint so should not be encountered
                ast::ExprForLoop(..) => unreachable!(),
                ast::ExprIfLet(..) => unreachable!(),
                ast::ExprWhileLet(..) => unreachable!(),
                _ => return
            },
            _ => return
        };

        let ty = cx.tcx.expr_ty(&*expr);
        if is_unrooted_ty(cx, ty, self.in_new_function) {
            cx.span_lint(UNROOTED_MUST_ROOT, expr.span,
                                     &format!("Expression of type {:?} must be rooted", ty))
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::Sender;
use std::time::{Duration, SystemTime};

use anyhow::{bail, Context, Result};
use async_std::task;
use clap::crate_version;
use log::{debug, info, warn};

use pueue_lib::network::message::*;
use pueue_lib::network::protocol::*;
use pueue_lib::network::secret::read_shared_secret;
use pueue_lib::state::SharedState;

use crate::network::follow_log::handle_follow;
use crate::network::message_handler::handle_message;

/// Poll the listener and accept new incoming connections.
/// Create a new future to handle the message and spawn it.
pub async fn accept_incoming(sender: Sender<Message>, state: SharedState) -> Result<()> {
    // Get cloned shared settings to avoid holding a mutex over an await point.
    let shared_settings = {
        let state = state.lock().unwrap();
        state.settings.shared.clone()
    };
    let listener = get_listener(&shared_settings).await?;
    let secret = read_shared_secret(&shared_settings.shared_secret_path())?;

    loop {
        // Poll incoming connections.
        let stream = match listener.accept().await {
            Ok(stream) => stream,
            Err(err) => {
                warn!("Failed connecting to client: {:?}", err);
                continue;
            }
        };

        // Start a new task for the request
        let sender_clone = sender.clone();
        let state_clone = state.clone();
        let secret_clone = secret.clone();
        task::spawn(async move {
            let _result = handle_incoming(stream, sender_clone, state_clone, secret_clone).await;
        });
    }
}

/// Continuously poll the existing incoming futures.
/// In case we received an instruction, handle it and create a response future.
/// The response future is added to unix_responses and handled in a separate function.
async fn handle_incoming(
    mut stream: GenericStream,
    sender: Sender<Message>,
    state: SharedState,
    secret: Vec<u8>,
) -> Result<()> {
    // Receive the secret once and check, whether the client is allowed to connect
    let payload_bytes = receive_bytes(&mut stream).await?;

    // Didn't receive any bytes. The client disconnected.
    if payload_bytes.is_empty() {
        info!("Client went away");
        return Ok(());
    }

    let start = SystemTime::now();

    // Return immediately, if we got a wrong secret from the client.
    if payload_bytes != secret {
        warn!(
            "Received invalid secret: {}",
            String::from_utf8(payload_bytes)?
        );

        // Always wait for 1 second, when getting a invalid secret.
        // This makes brute-forcing even more impossible and invalidates any timing attacks.
        let remaining_sleep_time = Duration::from_secs(1)
            - SystemTime::now()
                .duration_since(start)
                .context("Couldn't calculate duration. Did the system time change?")?;
        std::thread::sleep(remaining_sleep_time);
        bail!("Received invalid secret");
    }

    // Send a super short `ok` byte to the client, so it knows that the secret has been accepted.
    send_bytes(crate_version!().as_bytes(), &mut stream).await?;

    // Save the directory for convenience purposes and to prevent continuously
    // locking the state in the streaming loop.
    let pueue_directory = {
        let state = state.lock().unwrap();
        state.settings.shared.pueue_directory().clone()
    };

    loop {
        // Receive the actual instruction from the client
        let message = receive_message(&mut stream).await?;
        debug!("Received instruction: {:?}", message);

        let response = if let Message::StreamRequest(message) = message {
            // The client requested the output of a task.
            // Since we allow streaming, this needs to be handled seperately.
            handle_follow(&pueue_directory, &mut stream, &state, message).await?
        } else {
            // Process a normal message.
            handle_message(message, &sender, &state)
        };

        // Respond to the client.
        send_message(response, &mut stream).await?;
    }
}
<commit_msg>Report deserialization errors to the client<commit_after>use std::sync::mpsc::Sender;
use std::time::{Duration, SystemTime};

use anyhow::{bail, Context, Result};
use async_std::task;
use clap::crate_version;
use log::{debug, info, warn};

use pueue_lib::error::Error;
use pueue_lib::network::message::*;
use pueue_lib::network::protocol::*;
use pueue_lib::network::secret::read_shared_secret;
use pueue_lib::state::SharedState;

use crate::network::follow_log::handle_follow;
use crate::network::message_handler::handle_message;

/// Poll the listener and accept new incoming connections.
/// Create a new future to handle the message and spawn it.
pub async fn accept_incoming(sender: Sender<Message>, state: SharedState) -> Result<()> {
    // Get cloned shared settings to avoid holding a mutex over an await point.
    let shared_settings = {
        let state = state.lock().unwrap();
        state.settings.shared.clone()
    };
    let listener = get_listener(&shared_settings).await?;
    let secret = read_shared_secret(&shared_settings.shared_secret_path())?;

    loop {
        // Poll incoming connections.
        let stream = match listener.accept().await {
            Ok(stream) => stream,
            Err(err) => {
                warn!("Failed connecting to client: {:?}", err);
                continue;
            }
        };

        // Start a new task for the request
        let sender_clone = sender.clone();
        let state_clone = state.clone();
        let secret_clone = secret.clone();
        task::spawn(async move {
            let _result = handle_incoming(stream, sender_clone, state_clone, secret_clone).await;
        });
    }
}

/// Continuously poll the existing incoming futures.
/// In case we received an instruction, handle it and create a response future.
/// The response future is added to unix_responses and handled in a separate function.
async fn handle_incoming(
    mut stream: GenericStream,
    sender: Sender<Message>,
    state: SharedState,
    secret: Vec<u8>,
) -> Result<()> {
    // Receive the secret once and check, whether the client is allowed to connect
    let payload_bytes = receive_bytes(&mut stream).await?;

    // Didn't receive any bytes. The client disconnected.
    if payload_bytes.is_empty() {
        info!("Client went away");
        return Ok(());
    }

    let start = SystemTime::now();

    // Return immediately, if we got a wrong secret from the client.
    if payload_bytes != secret {
        warn!(
            "Received invalid secret: {}",
            String::from_utf8(payload_bytes)?
        );

        // Wait for 1 second before closing the socket, when getting a invalid secret.
        // This invalidates any timing attacks.
        let remaining_sleep_time = Duration::from_millis(1)
            - SystemTime::now()
                .duration_since(start)
                .context("Couldn't calculate duration. Did the system time change?")?;
        std::thread::sleep(remaining_sleep_time);
        bail!("Received invalid secret");
    }

    // Send a short `ok` byte to the client, so it knows that the secret has been accepted.
    // This is also the current version of the daemon, so the client can inform the user if the
    // daemon needs a restart in case a version difference exists.
    send_bytes(crate_version!().as_bytes(), &mut stream).await?;

    // Save the directory for convenience purposes and to prevent continuously
    // locking the state in the streaming loop.
    let pueue_directory = {
        let state = state.lock().unwrap();
        state.settings.shared.pueue_directory().clone()
    };

    loop {
        // Receive the actual instruction from the client
        let message_result = receive_message(&mut stream).await;

        // In case of a deserialization error, respond the error to the client and return early.
        if let Err(Error::MessageDeserialization(err)) = message_result {
            send_message(
                create_failure_message(format!("Failed to deserialize message: {}", err)),
                &mut stream,
            )
            .await?;
            return Ok(());
        }

        let message = message_result?;
        debug!("Received instruction: {:?}", message);

        let response = if let Message::StreamRequest(message) = message {
            // The client requested the output of a task.
            // Since we allow streaming, this needs to be handled seperately.
            handle_follow(&pueue_directory, &mut stream, &state, message).await?
        } else {
            // Process a normal message.
            handle_message(message, &sender, &state)
        };

        // Respond to the client.
        send_message(response, &mut stream).await?;
    }
}
<|endoftext|>


<commit_before>use crate::error::{Error,
                   Result};
use blake2b_simd::{Params,
                   State};
use hex::FromHex;
use serde::Serialize;
use std::{convert::TryInto,
          fmt,
          fs::File,
          io::{BufReader,
               Read},
          path::Path,
          str::FromStr};

/// When hashing byte streams, we'll read 1KB at a time, adding this to the
/// internal hashing state as we compute the final digest.
const BUF_SIZE: usize = 1024;

/// The size of our Blake2b hash digests (32 bytes)
const HASH_DIGEST_SIZE: usize = 32;

/// Convenience wrapper type for a 32-byte Blake2b hash digest.
///
/// Implements secure equality comparison, as well as hex-encoding via
/// `std::fmt::Display`.
///
/// There are intentionally no explicit constructors; to get a
/// instance, you'll need to either convert it directly from a `&[u8]`
/// or parse it from a hex string.
#[derive(Clone, Debug)]
pub struct Blake2bHash {
    digest: [u8; HASH_DIGEST_SIZE],
}

impl Blake2bHash {
    /// Calculate the BLAKE2b hash of the contents of a file.
    pub fn from_file<P>(filename: P) -> Result<Self>
        where P: AsRef<Path>
    {
        let file = File::open(filename.as_ref())?;
        let mut reader = BufReader::new(file);
        Self::from_reader(&mut reader)
    }

    /// Calculate the BLAKE2b hash of a sequence of bytes.
    pub fn from_bytes<B>(data: B) -> Self
        where B: AsRef<[u8]>
    {
        let mut state = hash_state();
        state.update(data.as_ref());
        state.finalize().into()
    }

    /// Calculate the BLAKE2b hash of a Read implentation.
    pub fn from_reader(reader: &mut dyn Read) -> Result<Self> {
        let mut state = hash_state();

        let mut buf = [0u8; BUF_SIZE];
        loop {
            let bytes_read = reader.read(&mut buf)?;
            if bytes_read == 0 {
                break;
            }
            let chunk = &buf[0..bytes_read];
            state.update(chunk);
        }

        Ok(state.finalize().into())
    }
}

// We *could* just wrap the `blake2b_simd::Hash` directly in our
// `Blake2bHash` type, but then we wouldn't be able to parse a
// `Blake2bHash` from a string, because `blake2b_simd::Hash does not
// have that ability. So, we'll just grab the bytes and call it a
// day.
impl From<blake2b_simd::Hash> for Blake2bHash {
    fn from(src: blake2b_simd::Hash) -> Self {
        let digest = src.as_bytes()
                        .try_into()
                        .expect("We know we can safely convert to a byte array");
        Blake2bHash { digest }
    }
}

impl AsRef<[u8]> for Blake2bHash {
    fn as_ref(&self) -> &[u8] { &self.digest }
}

impl PartialEq for Blake2bHash {
    /// Implement secure equality comparison for our hashes here so we
    /// don't have to think about it elsewhere.
    // Strictly speaking, secure equality comparison shouldn't be
    // necessary; however, having a type encapsulate this gives us a
    // convenient way to modify this in the future.
    fn eq(&self, other: &Blake2bHash) -> bool { crate::crypto::secure_eq(self, other) }
}

impl Eq for Blake2bHash {}

impl fmt::Display for Blake2bHash {
    /// Displays a Blake2bHash as a lowercase hex-encoded string.
    ///
    /// Due to historical precedent, the lowercasing *is* significant,
    /// as we sign the lowercase hex-encoded version of a Blake2b
    /// hash, and not simply the Blake2b hash itself, when we sign a
    /// HART file.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // hex::encode currently outputs lowercase strings, but we
        // want to strictly enforce this and guard against any future
        // changes to that crate.
        hex::encode(self).to_lowercase().fmt(f)
    }
}

impl FromStr for Blake2bHash {
    type Err = Error;

    /// Convert a hex-encoded byte string into a Blake2bHash. Ensures
    /// the string represents a byte array of proper length.
    ///
    /// Case of the incoming string is not significant (e.g.,
    /// "DEADBEEF" and "deadbeef" are equivalent).
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        // FromHex has an implementation for [u8; 32], so this ensures
        // the proper length of bytes... well, that and the compiler,
        // of course :)
        let bytes = FromHex::from_hex(s).map_err(|e| {
                                            Error::CryptoError(format!("Could not parse \
                                                                        Blake2bHash from string: \
                                                                        {}",
                                                                       e))
                                        })?;
        Ok(Self { digest: bytes })
    }
}

impl Serialize for Blake2bHash {
    /// Serializes a `Blake2bHash` according to its `Display`
    /// implementation (i.e., a lowercase hex-encoded string).
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
        where S: serde::Serializer
    {
        serializer.serialize_str(&self.to_string())
    }
}

////////////////////////////////////////////////////////////////////////

/// Initialize the hasher state. In particular, set the digest length
/// to 32 bytes. All hashing functions must use this to ensure
/// consistency!
fn hash_state() -> State {
    let mut params = Params::new();
    params.hash_length(HASH_DIGEST_SIZE);
    params.to_state()
}

#[cfg(test)]
mod test {
    #[allow(unused_imports)]
    use std::fs::{self,
                  File};
    #[allow(unused_imports)]
    use std::io;

    use super::{super::test_support::*,
                *};

    /// Helper function to create a Blake2bHash directly from a
    /// hex-encoded string.
    fn hash_from_hex(hex: &str) -> Blake2bHash { hex.parse().unwrap() }

    mod blake2bhash {
        use super::*;

        #[test]
        fn strings_can_be_hashed() {
            let message = "supercalifragilisticexpialadocious";
            let expected =
                hash_from_hex("2ca8ebafca7e189de2a36125b92a1db20f393d1e2708f5daa55e51cf05114437");
            let actual = Blake2bHash::from_bytes(message);

            assert_eq!(expected, actual);
        }

        #[test]
        fn bytes_can_be_hashed() {
            let message = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8];
            let expected =
                hash_from_hex("8b57a796a5d07cb04cc1614dfc2acb3f73edc712d7f433619ca3bbe66bb15f49");
            let actual = Blake2bHash::from_bytes(&message);

            assert_eq!(expected, actual);
        }

        #[test]
        fn hash_file_working() {
            // The expected values were computed using the `b2sum` program from
            // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
            //      b2sum -s=32 signme.dat

            let computed = Blake2bHash::from_file(&fixture("signme.dat")).unwrap();
            let expected =
                hash_from_hex("20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233");
            assert_eq!(computed, expected);

            let computed =
                Blake2bHash::from_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
            let expected =
                hash_from_hex("e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1");
            assert_eq!(computed, expected);

            let computed =
                Blake2bHash::from_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
            let expected =
                hash_from_hex("b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265");
            assert_eq!(computed, expected);
        }

        #[test]
        #[cfg(feature = "functional")]
        fn hash_file_large_binary() {
            let dir = tempfile::Builder::new().prefix("large_file")
                                              .tempdir()
                                              .unwrap();

            let url = "http://www.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
            let file = dir.path().join(url.rsplit('/').next().unwrap());

            // Download the doc to the temp directory
            let mut f = File::create(&file).unwrap();
            let mut res = reqwest::blocking::get(url).unwrap();
            res.copy_to(&mut f).unwrap();

            let computed = Blake2bHash::from_file(&file).unwrap();
            let expected =
                hash_from_hex("ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414");
            assert_eq!(computed, expected);
        }

        #[test]
        fn eq() {
            let zeroes = Blake2bHash { digest: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                                0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                                0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                                0u8, 0u8], };

            let ones = Blake2bHash { digest: [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                              1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                              1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                              1u8, 1u8], };

            assert_ne!(zeroes, ones);
            assert_eq!(zeroes, zeroes);
            assert_eq!(ones, ones);
        }

        #[test]
        fn display() {
            let ones = Blake2bHash { digest: [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                              1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                              1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                              1u8, 1u8], };
            assert_eq!(ones.to_string(),
                       "0101010101010101010101010101010101010101010101010101010101010101");
        }

        #[test]
        fn from_str_good() {
            // Exactly 32 bytes long
            let h = "0101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_ok());
        }

        #[test]
        fn from_str_short() {
            // This is one byte too short
            let h = "01010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_err());
        }
        #[test]
        fn from_str_long() {
            // This is one byte too long
            let h = "010101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
            assert!(h.is_err());
        }

        #[test]
        fn from_str_case_is_insignificant() {
            let lower_case = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let upper_case = "20590A52C4F00588C500328B16D466C982A26FABAA5FA4DCC83052DD0A84F233";

            let l = lower_case.parse::<Blake2bHash>().unwrap();
            let u = upper_case.parse::<Blake2bHash>().unwrap();

            assert_eq!(l, u);
        }

        #[test]
        fn from_str_display_round_trip() {
            let input = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let output = input.parse::<Blake2bHash>().unwrap().to_string();
            assert_eq!(output, input);
        }

        #[test]
        fn serialize_as_hex_encoding() {
            let input = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
            let hash: Blake2bHash = input.parse().unwrap();
            serde_test::assert_ser_tokens(&hash, &[serde_test::Token::Str(input)]);
        }
    }
}
<commit_msg>[REFACTOR] Clean up Blake2bHash tests<commit_after>use crate::error::{Error,
                   Result};
use blake2b_simd::{Params,
                   State};
use hex::FromHex;
use serde::Serialize;
use std::{convert::TryInto,
          fmt,
          fs::File,
          io::{BufReader,
               Read},
          path::Path,
          str::FromStr};

/// When hashing byte streams, we'll read 1KB at a time, adding this to the
/// internal hashing state as we compute the final digest.
const BUF_SIZE: usize = 1024;

/// The size of our Blake2b hash digests (32 bytes)
const HASH_DIGEST_SIZE: usize = 32;

/// Convenience wrapper type for a 32-byte Blake2b hash digest.
///
/// Implements secure equality comparison, as well as hex-encoding via
/// `std::fmt::Display`.
///
/// There are intentionally no explicit constructors; to get a
/// instance, you'll need to either convert it directly from a `&[u8]`
/// or parse it from a hex string.
#[derive(Clone, Debug)]
pub struct Blake2bHash {
    digest: [u8; HASH_DIGEST_SIZE],
}

impl Blake2bHash {
    /// Calculate the BLAKE2b hash of the contents of a file.
    pub fn from_file<P>(filename: P) -> Result<Self>
        where P: AsRef<Path>
    {
        let file = File::open(filename.as_ref())?;
        let mut reader = BufReader::new(file);
        Self::from_reader(&mut reader)
    }

    /// Calculate the BLAKE2b hash of a sequence of bytes.
    pub fn from_bytes<B>(data: B) -> Self
        where B: AsRef<[u8]>
    {
        let mut state = hash_state();
        state.update(data.as_ref());
        state.finalize().into()
    }

    /// Calculate the BLAKE2b hash of a Read implentation.
    pub fn from_reader(reader: &mut dyn Read) -> Result<Self> {
        let mut state = hash_state();

        let mut buf = [0u8; BUF_SIZE];
        loop {
            let bytes_read = reader.read(&mut buf)?;
            if bytes_read == 0 {
                break;
            }
            let chunk = &buf[0..bytes_read];
            state.update(chunk);
        }

        Ok(state.finalize().into())
    }
}

// We *could* just wrap the `blake2b_simd::Hash` directly in our
// `Blake2bHash` type, but then we wouldn't be able to parse a
// `Blake2bHash` from a string, because `blake2b_simd::Hash does not
// have that ability. So, we'll just grab the bytes and call it a
// day.
impl From<blake2b_simd::Hash> for Blake2bHash {
    fn from(src: blake2b_simd::Hash) -> Self {
        let digest = src.as_bytes()
                        .try_into()
                        .expect("We know we can safely convert to a byte array");
        Blake2bHash { digest }
    }
}

impl AsRef<[u8]> for Blake2bHash {
    fn as_ref(&self) -> &[u8] { &self.digest }
}

impl PartialEq for Blake2bHash {
    /// Implement secure equality comparison for our hashes here so we
    /// don't have to think about it elsewhere.
    // Strictly speaking, secure equality comparison shouldn't be
    // necessary; however, having a type encapsulate this gives us a
    // convenient way to modify this in the future.
    fn eq(&self, other: &Blake2bHash) -> bool { crate::crypto::secure_eq(self, other) }
}

impl Eq for Blake2bHash {}

impl fmt::Display for Blake2bHash {
    /// Displays a Blake2bHash as a lowercase hex-encoded string.
    ///
    /// Due to historical precedent, the lowercasing *is* significant,
    /// as we sign the lowercase hex-encoded version of a Blake2b
    /// hash, and not simply the Blake2b hash itself, when we sign a
    /// HART file.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // hex::encode currently outputs lowercase strings, but we
        // want to strictly enforce this and guard against any future
        // changes to that crate.
        hex::encode(self).to_lowercase().fmt(f)
    }
}

impl FromStr for Blake2bHash {
    type Err = Error;

    /// Convert a hex-encoded byte string into a Blake2bHash. Ensures
    /// the string represents a byte array of proper length.
    ///
    /// Case of the incoming string is not significant (e.g.,
    /// "DEADBEEF" and "deadbeef" are equivalent).
    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        // FromHex has an implementation for [u8; 32], so this ensures
        // the proper length of bytes... well, that and the compiler,
        // of course :)
        let bytes = FromHex::from_hex(s).map_err(|e| {
                                            Error::CryptoError(format!("Could not parse \
                                                                        Blake2bHash from string: \
                                                                        {}",
                                                                       e))
                                        })?;
        Ok(Self { digest: bytes })
    }
}

impl Serialize for Blake2bHash {
    /// Serializes a `Blake2bHash` according to its `Display`
    /// implementation (i.e., a lowercase hex-encoded string).
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
        where S: serde::Serializer
    {
        serializer.serialize_str(&self.to_string())
    }
}

////////////////////////////////////////////////////////////////////////

/// Initialize the hasher state. In particular, set the digest length
/// to 32 bytes. All hashing functions must use this to ensure
/// consistency!
fn hash_state() -> State {
    let mut params = Params::new();
    params.hash_length(HASH_DIGEST_SIZE);
    params.to_state()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::crypto::test_support::fixture;

    /// Helper function to create a Blake2bHash directly from a
    /// hex-encoded string.
    fn hash_from_hex(hex: &str) -> Blake2bHash { hex.parse().unwrap() }

    #[test]
    fn strings_can_be_hashed() {
        let message = "supercalifragilisticexpialadocious";
        let expected =
            hash_from_hex("2ca8ebafca7e189de2a36125b92a1db20f393d1e2708f5daa55e51cf05114437");
        let actual = Blake2bHash::from_bytes(message);

        assert_eq!(expected, actual);
    }

    #[test]
    fn bytes_can_be_hashed() {
        let message = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8];
        let expected =
            hash_from_hex("8b57a796a5d07cb04cc1614dfc2acb3f73edc712d7f433619ca3bbe66bb15f49");
        let actual = Blake2bHash::from_bytes(&message);

        assert_eq!(expected, actual);
    }

    #[test]
    fn hash_file_working() {
        // The expected values were computed using the `b2sum` program from
        // https://github.com/dchest/b2sum using the the `-s=32` option. For example:
        //      b2sum -s=32 signme.dat

        let computed = Blake2bHash::from_file(&fixture("signme.dat")).unwrap();
        let expected =
            hash_from_hex("20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233");
        assert_eq!(computed, expected);

        let computed =
            Blake2bHash::from_file(&fixture("happyhumans-20160424223347.sig.key")).unwrap();
        let expected =
            hash_from_hex("e966844bbc50b7a3a6d81e94dd38e27b92814b944095a8e55f1780921bfcfbe1");
        assert_eq!(computed, expected);

        let computed = Blake2bHash::from_file(&fixture("happyhumans-20160424223347.pub")).unwrap();
        let expected =
            hash_from_hex("b80c4f412f9a0a7727b6e6f115e1b5fa3bae79ad2fcf47f769ed4e42cfb12265");
        assert_eq!(computed, expected);
    }

    #[test]
    #[cfg(feature = "functional")]
    fn hash_file_large_binary() {
        let dir = tempfile::Builder::new().prefix("large_file")
                                          .tempdir()
                                          .unwrap();

        let url = "http://www.kernel.org/pub/linux/kernel/v4.x/linux-4.3.tar.gz";
        let file = dir.path().join(url.rsplit('/').next().unwrap());

        // Download the doc to the temp directory
        let mut f = File::create(&file).unwrap();
        let mut res = reqwest::blocking::get(url).unwrap();
        res.copy_to(&mut f).unwrap();

        let computed = Blake2bHash::from_file(&file).unwrap();
        let expected =
            hash_from_hex("ba640dc063f0ed27e60b38dbb7cf19778cf7805d9fc91eb129fb68b409d46414");
        assert_eq!(computed, expected);
    }

    #[test]
    fn eq() {
        let zeroes = Blake2bHash { digest: [0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
                                            0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8], };

        let ones = Blake2bHash { digest: [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                          1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                          1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8], };

        assert_ne!(zeroes, ones);
        assert_eq!(zeroes, zeroes);
        assert_eq!(ones, ones);
    }

    #[test]
    fn display() {
        let ones = Blake2bHash { digest: [1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                          1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8,
                                          1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8, 1u8], };
        assert_eq!(ones.to_string(),
                   "0101010101010101010101010101010101010101010101010101010101010101");
    }

    #[test]
    fn from_str_good() {
        // Exactly 32 bytes long
        let h = "0101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
        assert!(h.is_ok());
    }

    #[test]
    fn from_str_short() {
        // This is one byte too short
        let h =
            "01010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
        assert!(h.is_err());
    }
    #[test]
    fn from_str_long() {
        // This is one byte too long
        let h = "010101010101010101010101010101010101010101010101010101010101010101".parse::<Blake2bHash>();
        assert!(h.is_err());
    }

    #[test]
    fn from_str_case_is_insignificant() {
        let lower_case = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        let upper_case = "20590A52C4F00588C500328B16D466C982A26FABAA5FA4DCC83052DD0A84F233";

        let l = lower_case.parse::<Blake2bHash>().unwrap();
        let u = upper_case.parse::<Blake2bHash>().unwrap();

        assert_eq!(l, u);
    }

    #[test]
    fn from_str_display_round_trip() {
        let input = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        let output = input.parse::<Blake2bHash>().unwrap().to_string();
        assert_eq!(output, input);
    }

    #[test]
    fn serialize_as_hex_encoding() {
        let input = "20590a52c4f00588c500328b16d466c982a26fabaa5fa4dcc83052dd0a84f233";
        let hash: Blake2bHash = input.parse().unwrap();
        serde_test::assert_ser_tokens(&hash, &[serde_test::Token::Str(input)]);
    }
}
<|endoftext|>


<commit_before>extern crate reqwest;
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;
use std::error::Error;
use std::sync::{Arc, RwLock};
use reqwest::StatusCode;

#[derive(Clone, Debug, PartialEq)]
pub struct LinkResult {
    pub code: Option<StatusCode>,
    /// Whether the HTTP request didn't make it to getting a HTTP code
    pub error: Option<String>,
}

impl LinkResult {
    pub fn is_valid(&self) -> bool {
        if self.error.is_some() {
            return false;
        }

        if let Some(c) = self.code {
            return c.is_success();
        }

        true
    }

    pub fn message(&self) -> String {
        if let Some(ref e) = self.error {
            return e.clone();
        }

        if let Some(c) = self.code {
            return format!("{}", c);
        }

        "Unknown error".to_string()
    }
}

lazy_static! {
    // Keep history of link checks so a rebuild doesn't have to check again
    static ref LINKS: Arc<RwLock<HashMap<String, LinkResult>>> = Arc::new(RwLock::new(HashMap::new()));
}

pub fn check_url(url: &str) -> LinkResult {
    {
        let guard = LINKS.read().unwrap();
        if let Some(res) = guard.get(url) {
            return res.clone();
        }
    }

    // Need to actually do the link checking
    let res = match reqwest::get(url) {
        Ok(response) => LinkResult { code: Some(response.status()), error: None },
        Err(e) => LinkResult { code: None, error: Some(e.description().to_string()) },
    };

    LINKS.write().unwrap().insert(url.to_string(), res.clone());
    return res;
}

#[cfg(test)]
mod tests {
    use super::{LINKS, check_url};

    #[test]
    fn can_validate_ok_links() {
        let url = "https://google.com";
        let res = check_url(url);
        assert!(res.is_valid());
        assert!(LINKS.read().unwrap().get(url).is_some());
        let res = check_url(url);
        assert!(res.is_valid());
    }

    #[test]
    fn can_fail_404_links() {
        let res = check_url("https://google.comys");
        assert_eq!(res.is_valid(), false);
        assert!(res.code.is_none());
        assert!(res.error.is_some());
    }
}
<commit_msg>link_checker: Set Accept header<commit_after>extern crate reqwest;
#[macro_use]
extern crate lazy_static;

use reqwest::header::{qitem, Accept, Headers};
use reqwest::{mime, StatusCode};
use std::collections::HashMap;
use std::error::Error;
use std::sync::{Arc, RwLock};

#[derive(Clone, Debug, PartialEq)]
pub struct LinkResult {
    pub code: Option<StatusCode>,
    /// Whether the HTTP request didn't make it to getting a HTTP code
    pub error: Option<String>,
}

impl LinkResult {
    pub fn is_valid(&self) -> bool {
        if self.error.is_some() {
            return false;
        }

        if let Some(c) = self.code {
            return c.is_success();
        }

        true
    }

    pub fn message(&self) -> String {
        if let Some(ref e) = self.error {
            return e.clone();
        }

        if let Some(c) = self.code {
            return format!("{}", c);
        }

        "Unknown error".to_string()
    }
}

lazy_static! {
    // Keep history of link checks so a rebuild doesn't have to check again
    static ref LINKS: Arc<RwLock<HashMap<String, LinkResult>>> = Arc::new(RwLock::new(HashMap::new()));
}

pub fn check_url(url: &str) -> LinkResult {
    {
        let guard = LINKS.read().unwrap();
        if let Some(res) = guard.get(url) {
            return res.clone();
        }
    }

    let mut headers = Headers::new();
    headers.set(Accept(vec![qitem(mime::TEXT_HTML), qitem(mime::STAR_STAR)]));

    let client = reqwest::Client::new();

    // Need to actually do the link checking
    let res = match client.get(url).headers(headers).send() {
        Ok(response) => LinkResult {
            code: Some(response.status()),
            error: None,
        },
        Err(e) => LinkResult {
            code: None,
            error: Some(e.description().to_string()),
        },
    };

    LINKS.write().unwrap().insert(url.to_string(), res.clone());
    res
}

#[cfg(test)]
mod tests {
    use super::{check_url, LINKS};

    #[test]
    fn can_validate_ok_links() {
        let url = "https://google.com";
        let res = check_url(url);
        assert!(res.is_valid());
        assert!(LINKS.read().unwrap().get(url).is_some());
        let res = check_url(url);
        assert!(res.is_valid());
    }

    #[test]
    fn can_fail_404_links() {
        let res = check_url("https://google.comys");
        assert_eq!(res.is_valid(), false);
        assert!(res.code.is_none());
        assert!(res.error.is_some());
    }
}
<|endoftext|>