<commit_before>//! The middleware implementation with JSON Web Token support.
//!

use std::collections::HashMap;
use std::str::from_utf8;
use std::sync::Arc;
use std::vec::Vec;

use futures::future::{lazy, Future};
use futures::Stream;
use json::parse as parse_json;
use lapin_futures_rustls::lapin::channel::{
    BasicConsumeOptions, BasicProperties, BasicPublishOptions, QueueBindOptions,
    QueueDeclareOptions, QueueDeleteOptions, QueueUnbindOptions,
};
use lapin_futures_rustls::lapin::types::{AMQPValue, FieldTable};
use uuid::Uuid;

use error::PathfinderError;
use engine::{RESPONSE_EXCHANGE};
use engine::middleware::{
    TOKEN_VERIFY_ROUTING_KEY,
    TOKEN_VERIFY_EXCHANGE,
    TOKEN_USER_PROFILE_ROUTING_KEY,
    TOKEN_USER_PROFILE_EXCHANGE
};
use engine::middleware::base::{Middleware, MiddlewareFuture, CustomUserHeaders};
use engine::middleware::utils::get_permissions;
use engine::options::RpcOptions;
use engine::serializer::JsonMessage;
use rabbitmq::RabbitMQClient;

/// A middleware class, that will check a JSON Web Token in WebSocket message.
/// If token wasn't specified or it's invalid returns a `PathfinderError` object.
pub struct JwtTokenMiddleware;

impl JwtTokenMiddleware {
    /// Returns a new instance of `JwtTokenMiddleware` structure.
    pub fn new() -> JwtTokenMiddleware {
        JwtTokenMiddleware {}
    }

    fn verify_token(&self, token: String, rabbitmq_client: Arc<RabbitMQClient>)
        -> impl Future<Item=(), Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let rabbitmq_client_local = rabbitmq_client.clone();
        let options = Arc::new(RpcOptions::default()
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );

        // 1. Create a channel
        rabbitmq_client_local.get_channel()
        // 2. Declare a response queue
        .and_then(move |channel| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let queue_declare_options = QueueDeclareOptions {
                passive: false,
                durable: true,
                exclusive: true,
                auto_delete: false,
                ..Default::default()
            };

            channel
                .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
                .map(move |queue| (channel, queue, options))
        })
        // 3. Link the response queue the exchange
        .and_then(move |(channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (channel, queue, options))
        })
        // 4. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("microservice_name"), String::from("microservice-auth")),
                (String::from("request_url"), String::from("/auth/api/token/verify")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            channel
                .basic_publish(
                    TOKEN_VERIFY_EXCHANGE.clone(),
                    TOKEN_VERIFY_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (channel, queue, options))
        })
        // 5. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(channel, queue, options)| {
            channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (channel, queue, message.unwrap(), options))
                })
        })
        // 6. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (channel, queue, options, json))
        })
        // 7. Unbind the response queue from the exchange point
        .and_then(move |(channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (channel, options, json))
        })
        // 8. Delete the response queue
        .and_then(move |(channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| (channel, json))
        })
        // 9. Close the channel
        .and_then(move |(channel, json)| {
            channel.close(200, "Close the channel.").map(|_| json)
        })
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                let is_valid_token = json["content"]["is_valid"].as_bool().unwrap();
                match is_valid_response && is_valid_token {
                    true => Ok(()),
                    false => {
                        let message = String::from("Token is invalid.");
                        Err(PathfinderError::AuthenticationError(message))
                    }
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason -> {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }

    fn get_headers(&self, token: String, rabbitmq_client: Arc<RabbitMQClient>)
        -> impl Future<Item=CustomUserHeaders, Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let rabbitmq_client_local = rabbitmq_client.clone();
        let options = Arc::new(RpcOptions::default()
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );

        // 1. Create a channel
        rabbitmq_client_local.get_channel()
        // 2. Declare a response queue
        .and_then(move |channel| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let queue_declare_options = QueueDeclareOptions {
                passive: false,
                durable: true,
                exclusive: true,
                auto_delete: false,
                ..Default::default()
            };

            channel
                .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
                .map(move |queue| (channel, queue, options))
        })
        // 3. Link the response queue the exchange
        .and_then(move |(channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (channel, queue, options))
        })
        // 4. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("microservice_name"), String::from("microservice-auth")),
                (String::from("request_url"), String::from("/auth/api/users/profile")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            channel
                .basic_publish(
                    TOKEN_USER_PROFILE_EXCHANGE.clone(),
                    TOKEN_USER_PROFILE_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (channel, queue, options))
        })
        // 5. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(channel, queue, options)| {
            channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (channel, queue, message.unwrap(), options))
                })
        })
        // 6. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (channel, queue, options, json))
        })
        // 7. Unbind the response queue from the exchange point
        .and_then(move |(channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (channel, options, json))
        })
        // 8. Delete the response queue
        .and_then(move |(channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| (channel, json))
        })
        // 9. Close the channel
        .and_then(move |(channel, json)| {
            channel.close(200, "Close the channel.").map(|_| json)
        })
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                match is_valid_response {
                    true => {
                        let mut extra_headers: CustomUserHeaders = HashMap::new();
                        extra_headers.insert(String::from("permissions"), get_permissions(&json));
                        Ok(extra_headers)
                    },
                    false => Ok(HashMap::new())
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason -> {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }
}

impl Middleware for JwtTokenMiddleware {
    fn process_request(&self, message: JsonMessage, rabbitmq_client: Arc<RabbitMQClient>) -> MiddlewareFuture {
        // Extract a token from a JSON object
        let token = match message["token"].as_str() {
            Some(token) => String::from(token),
            _ => {
                return Box::new(lazy(move || {
                    let message = String::from("The `token` field must be specified.");
                    Err(PathfinderError::AuthenticationError(message))
                }))
            }
        };

        // Verify the passed JSON Web Token and extract permissions
        let verify_token_future = self.verify_token(token.clone(), rabbitmq_client.clone());
        let get_headers_future = self.get_headers(token.clone(), rabbitmq_client.clone());
        Box::new(verify_token_future.and_then(move |_| get_headers_future))
    }
}
<commit_msg>Fixed the issue with passing messages in requests to Auth/Auth microservice<commit_after>//! The middleware implementation with JSON Web Token support.
//!

use std::collections::HashMap;
use std::str::from_utf8;
use std::sync::Arc;
use std::vec::Vec;

use futures::future::{lazy, Future};
use futures::Stream;
use json::parse as parse_json;
use lapin_futures_rustls::lapin::channel::{
    BasicConsumeOptions, BasicProperties, BasicPublishOptions, QueueBindOptions,
    QueueDeclareOptions, QueueDeleteOptions, QueueUnbindOptions,
};
use lapin_futures_rustls::lapin::types::{AMQPValue, FieldTable};
use uuid::Uuid;

use error::PathfinderError;
use engine::{RESPONSE_EXCHANGE};
use engine::middleware::{
    TOKEN_VERIFY_ROUTING_KEY,
    TOKEN_VERIFY_EXCHANGE,
    TOKEN_USER_PROFILE_ROUTING_KEY,
    TOKEN_USER_PROFILE_EXCHANGE
};
use engine::middleware::base::{Middleware, MiddlewareFuture, CustomUserHeaders};
use engine::middleware::utils::get_permissions;
use engine::options::RpcOptions;
use engine::serializer::JsonMessage;
use rabbitmq::RabbitMQClient;

/// A middleware class, that will check a JSON Web Token in WebSocket message.
/// If token wasn't specified or it's invalid returns a `PathfinderError` object.
pub struct JwtTokenMiddleware;

impl JwtTokenMiddleware {
    /// Returns a new instance of `JwtTokenMiddleware` structure.
    pub fn new() -> JwtTokenMiddleware {
        JwtTokenMiddleware {}
    }

    fn verify_token(&self, message: JsonMessage, token: String, rabbitmq_client: Arc<RabbitMQClient>)
        -> impl Future<Item=(), Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let rabbitmq_client_local = rabbitmq_client.clone();
        let options = Arc::new(RpcOptions::default()
            .with_message(message.clone())
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );

        // 1. Create a channel
        rabbitmq_client_local.get_channel()
        // 2. Declare a response queue
        .and_then(move |channel| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let queue_declare_options = QueueDeclareOptions {
                passive: false,
                durable: true,
                exclusive: true,
                auto_delete: false,
                ..Default::default()
            };

            channel
                .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
                .map(move |queue| (channel, queue, options))
        })
        // 3. Link the response queue the exchange
        .and_then(move |(channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (channel, queue, options))
        })
        // 4. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("routing_key"), String::from("auth.token.verify")),
                (String::from("request_url"), String::from("/auth/api/token/verify")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            channel
                .basic_publish(
                    TOKEN_VERIFY_EXCHANGE.clone(),
                    TOKEN_VERIFY_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (channel, queue, options))
        })
        // 5. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(channel, queue, options)| {
            channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (channel, queue, message.unwrap(), options))
                })
        })
        // 6. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (channel, queue, options, json))
        })
        // 7. Unbind the response queue from the exchange point
        .and_then(move |(channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (channel, options, json))
        })
        // 8. Delete the response queue
        .and_then(move |(channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| (channel, json))
        })
        // 9. Close the channel
        .and_then(move |(channel, json)| {
            channel.close(200, "Close the channel.").map(|_| json)
        })
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                let is_valid_token = json["content"]["is_valid"].as_bool().unwrap();
                match is_valid_response && is_valid_token {
                    true => Ok(()),
                    false => {
                        let message = String::from("Token is invalid.");
                        Err(PathfinderError::AuthenticationError(message))
                    }
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason -> {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }

    fn get_headers(&self, message: JsonMessage, token: String, rabbitmq_client: Arc<RabbitMQClient>)
        -> impl Future<Item=CustomUserHeaders, Error=PathfinderError> + Sync + Send + 'static
    {
        let access_token = token.clone();
        let rabbitmq_client_local = rabbitmq_client.clone();
        let options = Arc::new(RpcOptions::default()
            .with_message(message.clone())
            .with_queue_name(Arc::new(format!("{}", Uuid::new_v4())))
        );

        // 1. Create a channel
        rabbitmq_client_local.get_channel()
        // 2. Declare a response queue
        .and_then(move |channel| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let queue_declare_options = QueueDeclareOptions {
                passive: false,
                durable: true,
                exclusive: true,
                auto_delete: false,
                ..Default::default()
            };

            channel
                .queue_declare(&queue_name, queue_declare_options, FieldTable::new())
                .map(move |queue| (channel, queue, options))
        })
        // 3. Link the response queue the exchange
        .and_then(move |(channel, queue, options)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_bind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueBindOptions::default(),
                    FieldTable::new()
                )
                .map(move |_| (channel, queue, options))
        })
        // 4. Publish message into the microservice queue and make ensure that it's delivered
        .and_then(move |(channel, queue, options)| {
            let publish_message_options = BasicPublishOptions {
                mandatory: true,
                immediate: false,
                ..Default::default()
            };

            let request_headers: Vec<(String, String)> = vec![
                (String::from("microservice_name"), String::from("microservice-auth")),
                (String::from("request_url"), String::from("/auth/api/users/profile")),
            ];
            let mut message_headers = FieldTable::new();
            for &(ref key, ref value) in request_headers.iter() {
                let header_name = key.to_string();
                let header_value = AMQPValue::LongString(value.to_string());
                message_headers.insert(header_name, header_value);
            }

            let message = options.get_message().unwrap().clone();
            let queue_name_response = options.get_queue_name().unwrap().clone();
            let event_name = message["event-name"].as_str().unwrap_or("null");
            let request_body = object!{ "access_token" => access_token };
            let basic_properties = BasicProperties::default()
                .with_content_type("application/json".to_string())    // Content type
                .with_headers(message_headers)                        // Headers for the message
                .with_delivery_mode(2)                                // Message must be persistent
                .with_reply_to(queue_name_response.to_string())       // Response queue
                .with_correlation_id(event_name.clone().to_string()); // Event name

            channel
                .basic_publish(
                    TOKEN_USER_PROFILE_EXCHANGE.clone(),
                    TOKEN_USER_PROFILE_ROUTING_KEY.clone(),
                    request_body.dump().as_bytes().to_vec(),
                    publish_message_options,
                    basic_properties
                )
                .map(move |_confirmation| (channel, queue, options))
        })
        // 5. Consume a response message from the queue, that was declared on the 2nd step
        .and_then(move |(channel, queue, options)| {
            channel
                .basic_consume(
                    &queue,
                    "response_consumer",
                    BasicConsumeOptions::default(),
                    FieldTable::new()
                )
                .and_then(move |stream| {
                    stream
                        .take(1)
                        .into_future()
                        .map_err(|(err, _)| err)
                        .map(move |(message, _)| (channel, queue, message.unwrap(), options))
                })
        })
        // 6. Prepare a response for a client, serialize and pass to the next processing stage
        .and_then(move |(channel, queue, message, options)| {
            let raw_data = from_utf8(&message.data).unwrap();
            let json = parse_json(raw_data).unwrap();

            channel
                .basic_ack(message.delivery_tag, false)
                .map(move |_confirmation| (channel, queue, options, json))
        })
        // 7. Unbind the response queue from the exchange point
        .and_then(move |(channel, _queue, options, json)| {
            let queue_name = options.get_queue_name().unwrap().clone();
            let routing_key = options.get_queue_name().unwrap().clone();

            channel
                .queue_unbind(
                    &queue_name,
                    RESPONSE_EXCHANGE.clone(),
                    &routing_key,
                    QueueUnbindOptions::default(),
                    FieldTable::new(),
                )
                .map(move |_| (channel, options, json))
        })
        // 8. Delete the response queue
        .and_then(move |(channel, options, json)| {
            let queue_delete_options = QueueDeleteOptions {
                if_unused: false,
                if_empty: false,
                ..Default::default()
            };
            let queue_name = options.get_queue_name().unwrap().clone();

            channel
                .queue_delete(&queue_name, queue_delete_options)
                .map(move |_| (channel, json))
        })
        // 9. Close the channel
        .and_then(move |(channel, json)| {
            channel.close(200, "Close the channel.").map(|_| json)
        })
        .then(move |result| match result {
            Ok(json) => {
                let has_errors = !json["error"].is_null();
                if has_errors {
                    let errors = json["error"].clone();
                    return Err(PathfinderError::MicroserviceError(errors))
                };

                let is_valid_response = !json["content"].is_null();
                match is_valid_response {
                    true => {
                        let mut extra_headers: CustomUserHeaders = HashMap::new();
                        extra_headers.insert(String::from("permissions"), get_permissions(&json));
                        Ok(extra_headers)
                    },
                    false => Ok(HashMap::new())
                }
            },
            Err(err) => {
                error!("Error in RabbitMQ client. Reason -> {}", err);
                let message = String::from("The request wasn't processed. Please, try once again.");
                Err(PathfinderError::MessageBrokerError(message))
            }
        })
    }
}

impl Middleware for JwtTokenMiddleware {
    fn process_request(&self, message: JsonMessage, rabbitmq_client: Arc<RabbitMQClient>) -> MiddlewareFuture {
        // Extract a token from a JSON object
        let token = match message["token"].as_str() {
            Some(token) => String::from(token),
            _ => {
                return Box::new(lazy(move || {
                    let message = String::from("The `token` field must be specified.");
                    Err(PathfinderError::AuthenticationError(message))
                }))
            }
        };

        // Verify the passed JSON Web Token and extract permissions
        let verify_token_future = self.verify_token(message.clone(),token.clone(), rabbitmq_client.clone());
        let get_headers_future = self.get_headers(message.clone(),token.clone(), rabbitmq_client.clone());
        Box::new(verify_token_future.and_then(move |_| get_headers_future))
    }
}
<|endoftext|>


<commit_before>use anyhow::*;
use ape;
use id3;
use lewton::inside_ogg::OggStreamReader;
use log::error;
use metaflac;
use mp3_duration;
use regex::Regex;
use std::fs;
use std::path::Path;
use mp4ameta;

use crate::utils;
use crate::utils::AudioFormat;

#[derive(Debug, Clone, PartialEq)]
pub struct SongTags {
	pub disc_number: Option<u32>,
	pub track_number: Option<u32>,
	pub title: Option<String>,
	pub duration: Option<u32>,
	pub artist: Option<String>,
	pub album_artist: Option<String>,
	pub album: Option<String>,
	pub year: Option<i32>,
}

#[cfg_attr(feature = "profile-index", flame)]
pub fn read(path: &Path) -> Option<SongTags> {
	let data = match utils::get_audio_format(path) {
		Some(AudioFormat::FLAC) => Some(read_flac(path)),
		Some(AudioFormat::MP3) => Some(read_id3(path)),
		Some(AudioFormat::MP4) => Some(read_mp4(path)),
		Some(AudioFormat::MPC) => Some(read_ape(path)),
		Some(AudioFormat::OGG) => Some(read_vorbis(path)),
		_ => None,
	};
	match data {
		Some(Ok(d)) => Some(d),
		Some(Err(e)) => {
			error!("Error while reading file metadata for '{:?}': {}", path, e);
			None
		}
		None => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_id3(path: &Path) -> Result<SongTags> {
	let tag = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("id3_tag_read");
		match id3::Tag::read_from_path(&path) {
			Ok(t) => Ok(t),
			Err(e) => {
				if let Some(t) = e.partial_tag {
					Ok(t)
				} else {
					Err(e)
				}
			}
		}?
	};
	let duration = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("mp3_duration");
		mp3_duration::from_path(&path)
			.map(|d| d.as_secs() as u32)
			.ok()
	};

	let artist = tag.artist().map(|s| s.to_string());
	let album_artist = tag.album_artist().map(|s| s.to_string());
	let album = tag.album().map(|s| s.to_string());
	let title = tag.title().map(|s| s.to_string());
	let disc_number = tag.disc();
	let track_number = tag.track();
	let year = tag
		.year()
		.map(|y| y as i32)
		.or_else(|| tag.date_released().and_then(|d| Some(d.year)))
		.or_else(|| tag.date_recorded().and_then(|d| Some(d.year)));

	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration,
		disc_number,
		track_number,
		year,
	})
}

fn read_ape_string(item: &ape::Item) -> Option<String> {
	match item.value {
		ape::ItemValue::Text(ref s) => Some(s.clone()),
		_ => None,
	}
}

fn read_ape_i32(item: &ape::Item) -> Option<i32> {
	match item.value {
		ape::ItemValue::Text(ref s) => s.parse::<i32>().ok(),
		_ => None,
	}
}

fn read_ape_x_of_y(item: &ape::Item) -> Option<u32> {
	match item.value {
		ape::ItemValue::Text(ref s) => {
			let format = Regex::new(r#"^\d+"#).unwrap();
			if let Some(m) = format.find(s) {
				s[m.start()..m.end()].parse().ok()
			} else {
				None
			}
		}
		_ => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_ape(path: &Path) -> Result<SongTags> {
	let tag = ape::read(path)?;
	let artist = tag.item("Artist").and_then(read_ape_string);
	let album = tag.item("Album").and_then(read_ape_string);
	let album_artist = tag.item("Album artist").and_then(read_ape_string);
	let title = tag.item("Title").and_then(read_ape_string);
	let year = tag.item("Year").and_then(read_ape_i32);
	let disc_number = tag.item("Disc").and_then(read_ape_x_of_y);
	let track_number = tag.item("Track").and_then(read_ape_x_of_y);
	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration: None,
		disc_number,
		track_number,
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_vorbis(path: &Path) -> Result<SongTags> {
	let file = fs::File::open(path)?;
	let source = OggStreamReader::new(file)?;

	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};

	for (key, value) in source.comment_hdr.comment_list {
		match key.as_str() {
			"TITLE" => tags.title = Some(value),
			"ALBUM" => tags.album = Some(value),
			"ARTIST" => tags.artist = Some(value),
			"ALBUMARTIST" => tags.album_artist = Some(value),
			"TRACKNUMBER" => tags.track_number = value.parse::<u32>().ok(),
			"DISCNUMBER" => tags.disc_number = value.parse::<u32>().ok(),
			"DATE" => tags.year = value.parse::<i32>().ok(),
			_ => (),
		}
	}

	Ok(tags)
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_flac(path: &Path) -> Result<SongTags> {
	let tag = metaflac::Tag::read_from_path(path)?;
	let vorbis = tag
		.vorbis_comments()
		.ok_or(anyhow!("Missing Vorbis comments"))?;
	let disc_number = vorbis
		.get("DISCNUMBER")
		.and_then(|d| d[0].parse::<u32>().ok());
	let year = vorbis.get("DATE").and_then(|d| d[0].parse::<i32>().ok());
	let mut streaminfo = tag.get_blocks(metaflac::BlockType::StreamInfo);
	let duration = match streaminfo.next() {
		Some(&metaflac::Block::StreamInfo(ref s)) => {
			Some((s.total_samples as u32 / s.sample_rate) as u32)
		}
		_ => None,
	};

	Ok(SongTags {
		artist: vorbis.artist().map(|v| v[0].clone()),
		album_artist: vorbis.album_artist().map(|v| v[0].clone()),
		album: vorbis.album().map(|v| v[0].clone()),
		title: vorbis.title().map(|v| v[0].clone()),
		duration,
		disc_number,
		track_number: vorbis.track(),
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_mp4(path: &Path) -> Result<SongTags> {
	let tag = mp4ameta::Tag::read_from_path(path)?;
	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};
	tags.artist = Some(tag.artist().unwrap().to_string());
	tags.album_artist = Some(tag.album_artist().unwrap().to_string());
	tags.album = Some(tag.album().unwrap().to_string());
	tags.title = Some(tag.title().unwrap().to_string());
	tags.duration = Some(tag.duration().unwrap() as u32);
	tags.disc_number = tag.disk_number().0.and_then(|d| Some(d as u32));
	tags.track_number = tag.track_number().0.and_then(|d| Some(d as u32));
	tags.year = tag.year().unwrap().parse::<i32>().ok();

	Ok(tags)
}

#[test]
fn test_read_metadata() {
	let sample_tags = SongTags {
		disc_number: Some(3),
		track_number: Some(1),
		title: Some("TEST TITLE".into()),
		artist: Some("TEST ARTIST".into()),
		album_artist: Some("TEST ALBUM ARTIST".into()),
		album: Some("TEST ALBUM".into()),
		duration: None,
		year: Some(2016),
	};
	let flac_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	let mp3_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	assert_eq!(read(Path::new("test/sample.mp3")).unwrap(), mp3_sample_tag);
	assert_eq!(read(Path::new("test/sample.ogg")).unwrap(), sample_tags);
	assert_eq!(
		read(Path::new("test/sample.flac")).unwrap(),
		flac_sample_tag
	);
}
<commit_msg>alphabetize mp4meta import<commit_after>use anyhow::*;
use ape;
use id3;
use lewton::inside_ogg::OggStreamReader;
use log::error;
use metaflac;
use mp3_duration;
use mp4ameta;
use regex::Regex;
use std::fs;
use std::path::Path;

use crate::utils;
use crate::utils::AudioFormat;

#[derive(Debug, Clone, PartialEq)]
pub struct SongTags {
	pub disc_number: Option<u32>,
	pub track_number: Option<u32>,
	pub title: Option<String>,
	pub duration: Option<u32>,
	pub artist: Option<String>,
	pub album_artist: Option<String>,
	pub album: Option<String>,
	pub year: Option<i32>,
}

#[cfg_attr(feature = "profile-index", flame)]
pub fn read(path: &Path) -> Option<SongTags> {
	let data = match utils::get_audio_format(path) {
		Some(AudioFormat::FLAC) => Some(read_flac(path)),
		Some(AudioFormat::MP3) => Some(read_id3(path)),
		Some(AudioFormat::MP4) => Some(read_mp4(path)),
		Some(AudioFormat::MPC) => Some(read_ape(path)),
		Some(AudioFormat::OGG) => Some(read_vorbis(path)),
		_ => None,
	};
	match data {
		Some(Ok(d)) => Some(d),
		Some(Err(e)) => {
			error!("Error while reading file metadata for '{:?}': {}", path, e);
			None
		}
		None => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_id3(path: &Path) -> Result<SongTags> {
	let tag = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("id3_tag_read");
		match id3::Tag::read_from_path(&path) {
			Ok(t) => Ok(t),
			Err(e) => {
				if let Some(t) = e.partial_tag {
					Ok(t)
				} else {
					Err(e)
				}
			}
		}?
	};
	let duration = {
		#[cfg(feature = "profile-index")]
		let _guard = flame::start_guard("mp3_duration");
		mp3_duration::from_path(&path)
			.map(|d| d.as_secs() as u32)
			.ok()
	};

	let artist = tag.artist().map(|s| s.to_string());
	let album_artist = tag.album_artist().map(|s| s.to_string());
	let album = tag.album().map(|s| s.to_string());
	let title = tag.title().map(|s| s.to_string());
	let disc_number = tag.disc();
	let track_number = tag.track();
	let year = tag
		.year()
		.map(|y| y as i32)
		.or_else(|| tag.date_released().and_then(|d| Some(d.year)))
		.or_else(|| tag.date_recorded().and_then(|d| Some(d.year)));

	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration,
		disc_number,
		track_number,
		year,
	})
}

fn read_ape_string(item: &ape::Item) -> Option<String> {
	match item.value {
		ape::ItemValue::Text(ref s) => Some(s.clone()),
		_ => None,
	}
}

fn read_ape_i32(item: &ape::Item) -> Option<i32> {
	match item.value {
		ape::ItemValue::Text(ref s) => s.parse::<i32>().ok(),
		_ => None,
	}
}

fn read_ape_x_of_y(item: &ape::Item) -> Option<u32> {
	match item.value {
		ape::ItemValue::Text(ref s) => {
			let format = Regex::new(r#"^\d+"#).unwrap();
			if let Some(m) = format.find(s) {
				s[m.start()..m.end()].parse().ok()
			} else {
				None
			}
		}
		_ => None,
	}
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_ape(path: &Path) -> Result<SongTags> {
	let tag = ape::read(path)?;
	let artist = tag.item("Artist").and_then(read_ape_string);
	let album = tag.item("Album").and_then(read_ape_string);
	let album_artist = tag.item("Album artist").and_then(read_ape_string);
	let title = tag.item("Title").and_then(read_ape_string);
	let year = tag.item("Year").and_then(read_ape_i32);
	let disc_number = tag.item("Disc").and_then(read_ape_x_of_y);
	let track_number = tag.item("Track").and_then(read_ape_x_of_y);
	Ok(SongTags {
		artist,
		album_artist,
		album,
		title,
		duration: None,
		disc_number,
		track_number,
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_vorbis(path: &Path) -> Result<SongTags> {
	let file = fs::File::open(path)?;
	let source = OggStreamReader::new(file)?;

	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};

	for (key, value) in source.comment_hdr.comment_list {
		match key.as_str() {
			"TITLE" => tags.title = Some(value),
			"ALBUM" => tags.album = Some(value),
			"ARTIST" => tags.artist = Some(value),
			"ALBUMARTIST" => tags.album_artist = Some(value),
			"TRACKNUMBER" => tags.track_number = value.parse::<u32>().ok(),
			"DISCNUMBER" => tags.disc_number = value.parse::<u32>().ok(),
			"DATE" => tags.year = value.parse::<i32>().ok(),
			_ => (),
		}
	}

	Ok(tags)
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_flac(path: &Path) -> Result<SongTags> {
	let tag = metaflac::Tag::read_from_path(path)?;
	let vorbis = tag
		.vorbis_comments()
		.ok_or(anyhow!("Missing Vorbis comments"))?;
	let disc_number = vorbis
		.get("DISCNUMBER")
		.and_then(|d| d[0].parse::<u32>().ok());
	let year = vorbis.get("DATE").and_then(|d| d[0].parse::<i32>().ok());
	let mut streaminfo = tag.get_blocks(metaflac::BlockType::StreamInfo);
	let duration = match streaminfo.next() {
		Some(&metaflac::Block::StreamInfo(ref s)) => {
			Some((s.total_samples as u32 / s.sample_rate) as u32)
		}
		_ => None,
	};

	Ok(SongTags {
		artist: vorbis.artist().map(|v| v[0].clone()),
		album_artist: vorbis.album_artist().map(|v| v[0].clone()),
		album: vorbis.album().map(|v| v[0].clone()),
		title: vorbis.title().map(|v| v[0].clone()),
		duration,
		disc_number,
		track_number: vorbis.track(),
		year,
	})
}

#[cfg_attr(feature = "profile-index", flame)]
fn read_mp4(path: &Path) -> Result<SongTags> {
	let tag = mp4ameta::Tag::read_from_path(path)?;
	let mut tags = SongTags {
		artist: None,
		album_artist: None,
		album: None,
		title: None,
		duration: None,
		disc_number: None,
		track_number: None,
		year: None,
	};
	tags.artist = Some(tag.artist().unwrap().to_string());
	tags.album_artist = Some(tag.album_artist().unwrap().to_string());
	tags.album = Some(tag.album().unwrap().to_string());
	tags.title = Some(tag.title().unwrap().to_string());
	tags.duration = Some(tag.duration().unwrap() as u32);
	tags.disc_number = tag.disk_number().0.and_then(|d| Some(d as u32));
	tags.track_number = tag.track_number().0.and_then(|d| Some(d as u32));
	tags.year = tag.year().unwrap().parse::<i32>().ok();

	Ok(tags)
}

#[test]
fn test_read_metadata() {
	let sample_tags = SongTags {
		disc_number: Some(3),
		track_number: Some(1),
		title: Some("TEST TITLE".into()),
		artist: Some("TEST ARTIST".into()),
		album_artist: Some("TEST ALBUM ARTIST".into()),
		album: Some("TEST ALBUM".into()),
		duration: None,
		year: Some(2016),
	};
	let flac_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	let mp3_sample_tag = SongTags {
		duration: Some(0),
		..sample_tags.clone()
	};
	assert_eq!(read(Path::new("test/sample.mp3")).unwrap(), mp3_sample_tag);
	assert_eq!(read(Path::new("test/sample.ogg")).unwrap(), sample_tags);
	assert_eq!(
		read(Path::new("test/sample.flac")).unwrap(),
		flac_sample_tag
	);
}
<|endoftext|>


<commit_before>use crate::pcapng::blocks::common::{opts_from_slice, read_to_string, read_to_vec};
use crate::errors::PcapError;
use crate::DataLink;
use std::io::Read;
use byteorder::{ByteOrder, ReadBytesExt};
use crate::peek_reader::PeekReader;
use std::borrow::Cow;

/// The Name Resolution Block (NRB) is used to support the correlation of numeric addresses
/// (present in the captured packets) and their corresponding canonical names and it is optional.
#[derive(Clone, Debug)]
pub struct NameResolutionBlock<'a> {

    /// Records
    pub records: Vec<Record<'a>>,

    /// Options
    pub options: Vec<NameResolutionOption<'a>>
}

impl<'a> NameResolutionBlock<'a> {

    pub fn from_slice<B:ByteOrder>(mut slice: &'a[u8]) -> Result<(Self, &'a[u8]), PcapError> {

        let mut records = Vec::new();

        loop {
            let (mut record, slice_tmp) = Record::from_slice::<B>(slice)?;
            slice = slice_tmp;

            if record.type_ == 0 {
                if record.length != 0 {
                    return Err(PcapError::InvalidField("NameResolutionBlock: nrb_record_end length != 0"));
                }

                break;
            }

            records.push(record);
        }

        let (options, slice) = NameResolutionOption::from_slice::<B>(slice)?;

        let block = NameResolutionBlock {
            records,
            options
        };

        Ok((block, slice))
    }
}

#[derive(Clone, Debug)]
pub struct Record<'a> {
    pub type_: u16,
    pub length: u16,
    pub value: &'a[u8]
}

impl<'a> Record<'a> {

    pub fn from_slice<B:ByteOrder>(mut slice: &'a[u8]) -> Result<(Self, &'a[u8]), PcapError> {

        let type_ = slice.read_u16::<B>()?;
        let length = slice.read_u16::<B>()?;

        if slice.len() < length as usize {
            return Err(PcapError::IncompleteBuffer(length as usize - slice.len()));
        }
        let value = &slice[..length as usize];

        let record = Record {
            type_,
            length,
            value
        };

        Ok((record, &slice[length as usize..]))
    }
}

#[derive(Clone, Debug)]
pub enum NameResolutionOption<'a> {
    /// The opt_comment option is a UTF-8 string containing human-readable comment text
    /// that is associated to the current block.
    Comment(&'a str),

    /// The ns_dnsname option is a UTF-8 string containing the name of the machine (DNS server) used to perform the name resolution.
    NsDnsName(&'a str),

    /// The ns_dnsIP4addr option specifies the IPv4 address of the DNS server.
    NsDnsIpv4Addr(&'a [u8]),

    /// The ns_dnsIP6addr option specifies the IPv6 address of the DNS server.
    NsDnsIpv6Addr(&'a [u8])
}

impl<'a> NameResolutionOption<'a> {

    fn from_slice<B:ByteOrder>(slice: &'a[u8]) -> Result<(Vec<Self>, &'a[u8]), PcapError> {

        opts_from_slice::<B, _, _>(slice, |mut slice, type_, len| {

            let opt = match type_ {

                1 => NameResolutionOption::Comment(std::str::from_utf8(slice)?),
                2 => NameResolutionOption::NsDnsName(std::str::from_utf8(slice)?),
                3 => {
                    if slice.len() != 4 {
                        return Err(PcapError::InvalidField("NameResolutionOption: NsDnsIpv4Addr length != 4"))
                    }
                    NameResolutionOption::NsDnsIpv4Addr(slice)
                },
                4 => {
                    if slice.len() != 16 {
                        return Err(PcapError::InvalidField("NameResolutionOption: NsDnsIpv6Addr length != 16"))
                    }
                    NameResolutionOption::NsDnsIpv6Addr(slice)
                },

                _ => return Err(PcapError::InvalidField("InterfaceDescriptionOption type invalid"))
            };

            Ok(opt)
        })
    }
}
<commit_msg>Improved NameResolutionBlock<commit_after>use crate::pcapng::blocks::common::{opts_from_slice, read_to_string, read_to_vec};
use crate::errors::PcapError;
use crate::DataLink;
use std::io::Read;
use byteorder::{ByteOrder, ReadBytesExt};
use crate::peek_reader::PeekReader;
use std::borrow::Cow;

/// The Name Resolution Block (NRB) is used to support the correlation of numeric addresses
/// (present in the captured packets) and their corresponding canonical names and it is optional.
#[derive(Clone, Debug)]
pub struct NameResolutionBlock<'a> {

    /// Records
    pub records: Vec<Record<'a>>,

    /// Options
    pub options: Vec<NameResolutionOption<'a>>
}

impl<'a> NameResolutionBlock<'a> {

    pub fn from_slice<B:ByteOrder>(mut slice: &'a[u8]) -> Result<(Self, &'a[u8]), PcapError> {

        let mut records = Vec::new();

        loop {
            let (mut record, slice_tmp) = Record::from_slice::<B>(slice)?;
            slice = slice_tmp;

            match record {
                Record::End => break,
                _ => records.push(record)
            }
        }

        let (options, slice) = NameResolutionOption::from_slice::<B>(slice)?;

        let block = NameResolutionBlock {
            records,
            options
        };

        Ok((block, slice))
    }
}

#[derive(Clone, Debug)]
pub enum Record<'a> {
    End,
    Ipv4(Ipv4Record<'a>),
    Ipv6(Ipv6Record<'a>),
    Unknown(UnknownRecord<'a>)
}

impl<'a> Record<'a> {

    pub fn from_slice<B:ByteOrder>(mut slice: &'a[u8]) -> Result<(Self, &'a[u8]), PcapError> {

        let type_ = slice.read_u16::<B>()?;
        let length = slice.read_u16::<B>()?;
        let pad_len = (4 - length % 4) % 4;

        if slice.len() < length as usize {
            return Err(PcapError::IncompleteBuffer(length as usize - slice.len()));
        }
        let value = &slice[..length as usize];

        let record = match type_ {
            0 => {
                if length != 0 {
                    return Err(PcapError::InvalidField("NameResolutionBlock: nrb_record_end length != 0"));
                }
                Record::End
            },
            1 => {
                let record = Ipv4Record::from_slice(value)?;
                Record::Ipv4(record)
            },
            2 => {
                let record = Ipv6Record::from_slice(value)?;
                Record::Ipv6(record)
            },
            _=> {
                let record = UnknownRecord::new(type_, length, value);
                Record::Unknown(record)
            }
        };

        let len = length as usize + pad_len as usize;

        Ok((record, &slice[len..]))
    }
}

#[derive(Clone, Debug)]
pub struct Ipv4Record<'a> {
    pub ip_addr: &'a [u8],
    pub names: Vec<&'a str>
}

impl<'a> Ipv4Record<'a> {

    pub fn from_slice(mut slice: &'a[u8]) -> Result<Self, PcapError> {

        if slice.len() < 6 as usize {
            return Err(PcapError::InvalidField("NameResolutionBlock: Ipv4Record len < 6"));
        }

        let ip_addr = &slice[..4];
        slice = &slice[4..];

        let mut names = vec![];
        while slice.len() != 0 {
            let (name, slice_tmp) = str_from_u8_null_terminated(slice)?;
            slice = slice_tmp;
            names.push(name);
        }

        let record = Ipv4Record {
            ip_addr,
            names
        };

        Ok(record)
    }
}

#[derive(Clone, Debug)]
pub struct Ipv6Record<'a> {
    pub ip_addr: &'a [u8],
    pub names: Vec<&'a str>
}

impl<'a> Ipv6Record<'a> {

    pub fn from_slice(mut slice: &'a[u8]) -> Result<Self, PcapError> {

        if slice.len() < 18 as usize {
            return Err(PcapError::InvalidField("NameResolutionBlock: Ipv6Record len < 18"));
        }

        let ip_addr = &slice[..18];
        slice = &slice[18..];

        let mut names = vec![];
        while slice.len() != 0 {
            let (name, slice_tmp) = str_from_u8_null_terminated(slice)?;
            slice = slice_tmp;
            names.push(name);
        }

        let record = Ipv6Record {
            ip_addr,
            names
        };

        Ok(record)
    }
}

#[derive(Clone, Debug)]
pub struct UnknownRecord<'a> {
    pub type_: u16,
    pub length: u16,
    pub value: &'a [u8]
}

impl<'a> UnknownRecord<'a> {

    fn new(type_: u16, length: u16, value: &'a[u8]) -> Self {
        UnknownRecord {
            type_,
            length,
            value
        }
    }
}

#[derive(Clone, Debug)]
pub enum NameResolutionOption<'a> {
    /// The opt_comment option is a UTF-8 string containing human-readable comment text
    /// that is associated to the current block.
    Comment(&'a str),

    /// The ns_dnsname option is a UTF-8 string containing the name of the machine (DNS server) used to perform the name resolution.
    NsDnsName(&'a str),

    /// The ns_dnsIP4addr option specifies the IPv4 address of the DNS server.
    NsDnsIpv4Addr(&'a [u8]),

    /// The ns_dnsIP6addr option specifies the IPv6 address of the DNS server.
    NsDnsIpv6Addr(&'a [u8])
}

impl<'a> NameResolutionOption<'a> {

    fn from_slice<B:ByteOrder>(slice: &'a[u8]) -> Result<(Vec<Self>, &'a[u8]), PcapError> {

        opts_from_slice::<B, _, _>(slice, |mut slice, type_, len| {

            let opt = match type_ {

                1 => NameResolutionOption::Comment(std::str::from_utf8(slice)?),
                2 => NameResolutionOption::NsDnsName(std::str::from_utf8(slice)?),
                3 => {
                    if slice.len() != 4 {
                        return Err(PcapError::InvalidField("NameResolutionOption: NsDnsIpv4Addr length != 4"))
                    }
                    NameResolutionOption::NsDnsIpv4Addr(slice)
                },
                4 => {
                    if slice.len() != 16 {
                        return Err(PcapError::InvalidField("NameResolutionOption: NsDnsIpv6Addr length != 16"))
                    }
                    NameResolutionOption::NsDnsIpv6Addr(slice)
                },

                _ => return Err(PcapError::InvalidField("InterfaceDescriptionOption type invalid"))
            };

            Ok(opt)
        })
    }
}

pub fn str_from_u8_null_terminated(src: &[u8]) -> Result<(&str, &[u8]), PcapError> {
    let nul_range_end = src.iter()
        .position(|&c| c == b'\0')
        .ok_or(PcapError::InvalidField("Non null terminated string"))?;

    let s = std::str::from_utf8(&src[0..nul_range_end])?;
    let end = &src[nul_range_end..];

    Ok((s, end))
}

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

#![feature(macro_rules, plugin_registrar, quote, phase)]

//! Exports macros for use in other Servo crates.

#[cfg(test)]
extern crate sync;

#[macro_export]
macro_rules! bitfield(
    ($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => (
        impl $bitfieldname {
            #[inline]
            pub fn $getter(self) -> bool {
                let $bitfieldname(this) = self;
                (this & $value) != 0
            }

            #[inline]
            pub fn $setter(&mut self, value: bool) {
                let $bitfieldname(this) = *self;
                *self = $bitfieldname((this & !$value) | (if value { $value } else { 0 }))
            }
        }
    )
)

#[macro_export]
macro_rules! lazy_init(
    ($(static ref $N:ident : $T:ty = $e:expr;)*) => (
        $(
            #[allow(non_camel_case_types)]
            struct $N {__unit__: ()}
            static $N: $N = $N {__unit__: ()};
            impl Deref<$T> for $N {
                fn deref<'a>(&'a self) -> &'a $T {
                    unsafe {
                        static mut s: *const $T = 0 as *const $T;
                        static mut ONCE: ::sync::one::Once = ::sync::one::ONCE_INIT;
                        ONCE.doit(|| {
                            s = ::std::mem::transmute::<Box<$T>, *const $T>(box () ($e));
                        });
                        &*s
                    }
                }
            }

        )*
    )
)

#[cfg(test)]
mod tests {
    use std::collections::hashmap::HashMap;
    lazy_init! {
        static ref NUMBER: uint = times_two(3);
        static ref VEC: [Box<uint>, ..3] = [box 1, box 2, box 3];
        static ref OWNED_STRING: String = "hello".to_string();
        static ref HASHMAP: HashMap<uint, &'static str> = {
            let mut m = HashMap::new();
            m.insert(0u, "abc");
            m.insert(1, "def");
            m.insert(2, "ghi");
            m
        };
    }

    fn times_two(n: uint) -> uint {
        n * 2
    }

    #[test]
    fn test_basic() {
        assert_eq!(*OWNED_STRING, "hello".to_string());
        assert_eq!(*NUMBER, 6);
        assert!(HASHMAP.find(&1).is_some());
        assert!(HASHMAP.find(&3).is_none());
        assert_eq!(VEC.as_slice(), &[box 1, box 2, box 3]);
    }

    #[test]
    fn test_repeat() {
        assert_eq!(*NUMBER, 6);
        assert_eq!(*NUMBER, 6);
        assert_eq!(*NUMBER, 6);
    }
}
<commit_msg>Add lint for type-checking transmutes<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/. */

#![feature(macro_rules, plugin_registrar, quote, phase)]

//! Exports macros for use in other Servo crates.

extern crate syntax;

#[phase(plugin, link)]
extern crate rustc;
#[cfg(test)]
extern crate sync;

use syntax::ast;
use syntax::parse::token;
use rustc::lint::{Context, LintPass, LintPassObject, LintArray};
use rustc::plugin::Registry;
use rustc::middle::ty::{expr_ty, get};
use rustc::middle::typeck::astconv::AstConv;
use rustc::util::ppaux::Repr;

declare_lint!(TRANSMUTE_TYPE_LINT, Allow,
              "Warn and report types being transmuted")

struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(TRANSMUTE_TYPE_LINT)
    }

    fn check_expr(&mut self, cx: &Context, ex: &ast::Expr) {
        match ex.node {
            ast::ExprCall(ref expr, ref args) => {
                match expr.node {
                    ast::ExprPath(ref path) => {
                        if path.segments.last()
                                        .map_or(false, |ref segment| segment.identifier.name.as_str() == "transmute")
                           && args.len() == 1 {
                            let tcx = cx.tcx();
                            cx.span_lint(TRANSMUTE_TYPE_LINT, ex.span,
                                         format!("Transmute from {} to {} detected",
                                                 expr_ty(tcx, ex).repr(tcx),
                                                 expr_ty(tcx, &**args.get(0)).repr(tcx)
                                        ).as_slice());
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_lint_pass(box Pass as LintPassObject);
}

#[macro_export]
macro_rules! bitfield(
    ($bitfieldname:ident, $getter:ident, $setter:ident, $value:expr) => (
        impl $bitfieldname {
            #[inline]
            pub fn $getter(self) -> bool {
                let $bitfieldname(this) = self;
                (this & $value) != 0
            }

            #[inline]
            pub fn $setter(&mut self, value: bool) {
                let $bitfieldname(this) = *self;
                *self = $bitfieldname((this & !$value) | (if value { $value } else { 0 }))
            }
        }
    )
)

#[macro_export]
macro_rules! lazy_init(
    ($(static ref $N:ident : $T:ty = $e:expr;)*) => (
        $(
            #[allow(non_camel_case_types)]
            struct $N {__unit__: ()}
            static $N: $N = $N {__unit__: ()};
            impl Deref<$T> for $N {
                fn deref<'a>(&'a self) -> &'a $T {
                    unsafe {
                        static mut s: *const $T = 0 as *const $T;
                        static mut ONCE: ::sync::one::Once = ::sync::one::ONCE_INIT;
                        ONCE.doit(|| {
                            s = ::std::mem::transmute::<Box<$T>, *const $T>(box () ($e));
                        });
                        &*s
                    }
                }
            }

        )*
    )
)

#[cfg(test)]
mod tests {
    use std::collections::hashmap::HashMap;
    lazy_init! {
        static ref NUMBER: uint = times_two(3);
        static ref VEC: [Box<uint>, ..3] = [box 1, box 2, box 3];
        static ref OWNED_STRING: String = "hello".to_string();
        static ref HASHMAP: HashMap<uint, &'static str> = {
            let mut m = HashMap::new();
            m.insert(0u, "abc");
            m.insert(1, "def");
            m.insert(2, "ghi");
            m
        };
    }

    fn times_two(n: uint) -> uint {
        n * 2
    }

    #[test]
    fn test_basic() {
        assert_eq!(*OWNED_STRING, "hello".to_string());
        assert_eq!(*NUMBER, 6);
        assert!(HASHMAP.find(&1).is_some());
        assert!(HASHMAP.find(&3).is_none());
        assert_eq!(VEC.as_slice(), &[box 1, box 2, box 3]);
    }

    #[test]
    fn test_repeat() {
        assert_eq!(*NUMBER, 6);
        assert_eq!(*NUMBER, 6);
        assert_eq!(*NUMBER, 6);
    }
}
<|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 basedir::default_config_dir;
use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    pub static ref PREFS: Preferences = {
        let prefs = read_prefs().unwrap_or(HashMap::new());
        Preferences(Arc::new(Mutex::new(prefs)))
    };
}

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Number(f64),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            Json::F64(x) => PrefValue::Number(x),
            Json::I64(x) => PrefValue::Number(x as f64),
            Json::U64(x) => PrefValue::Number(x as f64),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }

    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            PrefValue::Number(x) => Some(x as i64),
            _ => None,
        }
    }

    pub fn as_u64(&self) -> Option<u64> {
        match *self {
            PrefValue::Number(x) => Some(x as u64),
            _ => None,
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            },
            PrefValue::Number(x) => {
                Json::F64(x)
            },
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
            }
        }
    }
    Ok(prefs)
}

pub fn add_user_prefs() {
    match opts::get().config_dir {
        Some(ref config_path) => {
            let mut path = PathBuf::from(config_path);
            init_user_prefs(&mut path);
        }
        None => {
            let mut path = default_config_dir().unwrap();
            if path.join("prefs.json").exists() {
                init_user_prefs(&mut path);
            }
        }
    }
}

fn init_user_prefs(path: &mut PathBuf) {
    path.push("prefs.json");
    if let Ok(file) = File::open(path) {
        if let Ok(prefs) = read_prefs_from_file(file) {
            PREFS.extend(prefs);
        }
    } else {
    writeln!(&mut stderr(), "Error opening prefs.json from config directory")
        .expect("failed printing to stderr");
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub struct Preferences(Arc<Mutex<HashMap<String, Pref>>>);

impl Preferences {
    pub fn get(&self, name: &str) -> Arc<PrefValue> {
        self.0.lock().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
    }

    pub fn cloned(&self) -> HashMap<String, Pref> {
        self.0.lock().unwrap().clone()
    }

    pub fn is_mozbrowser_enabled(&self) -> bool {
        self.get("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
    }

    pub fn set(&self, name: &str, value: PrefValue) {
        let mut prefs = self.0.lock().unwrap();
        if let Some(pref) = prefs.get_mut(name) {
            pref.set(value);
            return;
        }
        prefs.insert(name.to_owned(), Pref::new(value));
    }

    pub fn reset(&self, name: &str) -> Arc<PrefValue> {
        let mut prefs = self.0.lock().unwrap();
        let result = match prefs.get_mut(name) {
            None => return Arc::new(PrefValue::Missing),
            Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
            Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
                *set_value = None;
                default.clone()
            },
        };
        if *result == PrefValue::Missing {
            prefs.remove(name);
        }
        result
    }

    pub fn reset_all(&self) {
        let names = {
            self.0.lock().unwrap().keys().cloned().collect::<Vec<String>>()
        };
        for name in names.iter() {
            self.reset(name);
        }
    }

    pub fn extend(&self, extension: HashMap<String, Pref>) {
        self.0.lock().unwrap().extend(extension);
    }
}
<commit_msg>Only allocate a `HashMap` if we need to.<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 basedir::default_config_dir;
use opts;
use resource_files::resources_dir_path;
use rustc_serialize::json::{Json, ToJson};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, Write, stderr};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

lazy_static! {
    pub static ref PREFS: Preferences = {
        let prefs = read_prefs().unwrap_or_else(|_| HashMap::new());
        Preferences(Arc::new(Mutex::new(prefs)))
    };
}

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum PrefValue {
    Boolean(bool),
    String(String),
    Number(f64),
    Missing
}

impl PrefValue {
    pub fn from_json(data: Json) -> Result<PrefValue, ()> {
        let value = match data {
            Json::Boolean(x) => PrefValue::Boolean(x),
            Json::String(x) => PrefValue::String(x),
            Json::F64(x) => PrefValue::Number(x),
            Json::I64(x) => PrefValue::Number(x as f64),
            Json::U64(x) => PrefValue::Number(x as f64),
            _ => return Err(())
        };
        Ok(value)
    }

    pub fn as_boolean(&self) -> Option<bool> {
        match *self {
            PrefValue::Boolean(value) => {
                Some(value)
            },
            _ => None
        }
    }

    pub fn as_string(&self) -> Option<&str> {
        match *self {
            PrefValue::String(ref value) => {
                Some(&value)
            },
            _ => None
        }
    }

    pub fn as_i64(&self) -> Option<i64> {
        match *self {
            PrefValue::Number(x) => Some(x as i64),
            _ => None,
        }
    }

    pub fn as_u64(&self) -> Option<u64> {
        match *self {
            PrefValue::Number(x) => Some(x as u64),
            _ => None,
        }
    }
}

impl ToJson for PrefValue {
    fn to_json(&self) -> Json {
        match *self {
            PrefValue::Boolean(x) => {
                Json::Boolean(x)
            },
            PrefValue::String(ref x) => {
                Json::String(x.clone())
            },
            PrefValue::Number(x) => {
                Json::F64(x)
            },
            PrefValue::Missing => Json::Null
        }
    }
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum Pref {
    NoDefault(Arc<PrefValue>),
    WithDefault(Arc<PrefValue>, Option<Arc<PrefValue>>)
}

impl Pref {
    pub fn new(value: PrefValue) -> Pref {
        Pref::NoDefault(Arc::new(value))
    }

    fn new_default(value: PrefValue) -> Pref {
        Pref::WithDefault(Arc::new(value), None)
    }

    fn from_json(data: Json) -> Result<Pref, ()> {
        let value = try!(PrefValue::from_json(data));
        Ok(Pref::new_default(value))
    }

    pub fn value(&self) -> &Arc<PrefValue> {
        match *self {
            Pref::NoDefault(ref x) => x,
            Pref::WithDefault(ref default, ref override_value) => {
                match *override_value {
                    Some(ref x) => x,
                    None => default
                }
            }
        }
    }

    fn set(&mut self, value: PrefValue) {
        // TODO - this should error if we try to override a pref of one type
        // with a value of a different type
        match *self {
            Pref::NoDefault(ref mut pref_value) => {
                *pref_value = Arc::new(value)
            },
            Pref::WithDefault(_, ref mut override_value) => {
                *override_value = Some(Arc::new(value))
            }
        }
    }
}

impl ToJson for Pref {
    fn to_json(&self) -> Json {
        self.value().to_json()
    }
}

pub fn read_prefs_from_file<T>(mut file: T)
    -> Result<HashMap<String, Pref>, ()> where T: Read {
    let json = try!(Json::from_reader(&mut file).or_else(|e| {
        println!("Ignoring invalid JSON in preferences: {:?}.", e);
        Err(())
    }));

    let mut prefs = HashMap::new();
    if let Json::Object(obj) = json {
        for (name, value) in obj.into_iter() {
            match Pref::from_json(value) {
                Ok(x) => {
                    prefs.insert(name, x);
                },
                Err(_) => println!("Ignoring non-boolean/string/i64 preference value for {:?}", name),
            }
        }
    }
    Ok(prefs)
}

pub fn add_user_prefs() {
    match opts::get().config_dir {
        Some(ref config_path) => {
            let mut path = PathBuf::from(config_path);
            init_user_prefs(&mut path);
        }
        None => {
            let mut path = default_config_dir().unwrap();
            if path.join("prefs.json").exists() {
                init_user_prefs(&mut path);
            }
        }
    }
}

fn init_user_prefs(path: &mut PathBuf) {
    path.push("prefs.json");
    if let Ok(file) = File::open(path) {
        if let Ok(prefs) = read_prefs_from_file(file) {
            PREFS.extend(prefs);
        }
    } else {
    writeln!(&mut stderr(), "Error opening prefs.json from config directory")
        .expect("failed printing to stderr");
    }
}

fn read_prefs() -> Result<HashMap<String, Pref>, ()> {
    let mut path = resources_dir_path();
    path.push("prefs.json");

    let file = try!(File::open(path).or_else(|e| {
        writeln!(&mut stderr(), "Error opening preferences: {:?}.", e)
            .expect("failed printing to stderr");
        Err(())
    }));

    read_prefs_from_file(file)
}

pub struct Preferences(Arc<Mutex<HashMap<String, Pref>>>);

impl Preferences {
    pub fn get(&self, name: &str) -> Arc<PrefValue> {
        self.0.lock().unwrap().get(name).map_or(Arc::new(PrefValue::Missing), |x| x.value().clone())
    }

    pub fn cloned(&self) -> HashMap<String, Pref> {
        self.0.lock().unwrap().clone()
    }

    pub fn is_mozbrowser_enabled(&self) -> bool {
        self.get("dom.mozbrowser.enabled").as_boolean().unwrap_or(false)
    }

    pub fn set(&self, name: &str, value: PrefValue) {
        let mut prefs = self.0.lock().unwrap();
        if let Some(pref) = prefs.get_mut(name) {
            pref.set(value);
            return;
        }
        prefs.insert(name.to_owned(), Pref::new(value));
    }

    pub fn reset(&self, name: &str) -> Arc<PrefValue> {
        let mut prefs = self.0.lock().unwrap();
        let result = match prefs.get_mut(name) {
            None => return Arc::new(PrefValue::Missing),
            Some(&mut Pref::NoDefault(_)) => Arc::new(PrefValue::Missing),
            Some(&mut Pref::WithDefault(ref default, ref mut set_value)) => {
                *set_value = None;
                default.clone()
            },
        };
        if *result == PrefValue::Missing {
            prefs.remove(name);
        }
        result
    }

    pub fn reset_all(&self) {
        let names = {
            self.0.lock().unwrap().keys().cloned().collect::<Vec<String>>()
        };
        for name in names.iter() {
            self.reset(name);
        }
    }

    pub fn extend(&self, extension: HashMap<String, Pref>) {
        self.0.lock().unwrap().extend(extension);
    }
}
<|endoftext|>


<commit_before>pub use telegram_bot_raw::{Integer, Float, True};
pub use telegram_bot_raw::{Update, UpdateKind, RawUpdate};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat, RawChat};
pub use telegram_bot_raw::{Message, MessageKind, RawMessage, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind, RawMessageEntity};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue};

pub use telegram_bot_raw::{ParseMode, ChatId, MessageId};
pub use telegram_bot_raw::{ReplyMarkup, InlineKeyboardMarkup, ReplyKeyboardMarkup};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{GetMe, ForwardMessage, SendLocation, SendMessage};
pub use telegram_bot_raw::{ChatAction, SendChatAction};
<commit_msg>feat: reexport Request from telegram-bot-raw<commit_after>pub use telegram_bot_raw::{Integer, Float, True, Request};
pub use telegram_bot_raw::{Update, UpdateKind, RawUpdate};
pub use telegram_bot_raw::{User, Group, Supergroup, Channel, Chat, RawChat};
pub use telegram_bot_raw::{Message, MessageKind, RawMessage, Forward, ForwardFrom};
pub use telegram_bot_raw::{MessageEntity, MessageEntityKind, RawMessageEntity};
pub use telegram_bot_raw::{Audio, Document, PhotoSize, Sticker, Video, Voice};
pub use telegram_bot_raw::{Contact, Location, Venue};

pub use telegram_bot_raw::{ParseMode, ChatId, MessageId};
pub use telegram_bot_raw::{ReplyMarkup, InlineKeyboardMarkup, ReplyKeyboardMarkup};
pub use telegram_bot_raw::{ReplyKeyboardRemove, ForceReply};
pub use telegram_bot_raw::{GetMe, ForwardMessage, SendLocation, SendMessage};
pub use telegram_bot_raw::{ChatAction, SendChatAction};
<|endoftext|>


<commit_before>use typedef::*;

pub const PREAMBLE: &str = "BAKER1";

/// Stops the program and shuts down the vm
/// `halt`
pub const HALT: Byte = 0x01;

/// Adds the two top most values and pushes the result back to the data stack.
/// This also removes the processed values from the data stack.
/// ```
/// add
/// ```
pub const ADD: Byte = 0x02;

/// Subtracts the first value on the data stack from the second and pushes the
/// result back to the data stack. This also removes the processed values from
/// the data stack.
/// ```
/// sub
/// ```
pub const SUB: Byte = 0x03;

/// Adds the two top most values and pushes the result back to the data stack.
/// This also removes the processed values from the data stack.
/// ```
/// mul
/// ```
pub const MUL: Byte = 0x04;

/// Divides the second value on the data stack throuh the first one and pushes
/// the result back to the top of the data stack. This also removes the
/// processed values from the data stack.
/// ```
/// div
/// ```
pub const DIV: Byte = 0x05;

/// Prints out the top most value on the data stack
#[deprecated(since="0.1.0", note="will be replaced soon")]
pub const PRINT: Byte = 0x06;

/// Pushes a value (Word) to the data stack
/// ```
/// push WORD
/// ```
pub const PUSH: Byte = 0x07;

/// An unconditional jump to the specified address
/// ```
/// jmp ADDRESS
/// ```
pub const JMP: Byte = 0x08;

/// Jumps to the specified address if the top most value on the data stack
/// equals 0
/// ```
/// jz ADDRESS
/// ```
pub const JZ: Byte = 0x09;

/// Jumps to the specified address if the top most value on the data stack is
/// not equal to 0
/// ```
/// jnz ADDRESS
/// ```
pub const JNZ: Byte = 0x0A;

/// Moves the specified value (Word) to the specified register (Address)
/// ```
/// movw WORD, ADDRESS
/// ```
pub const MOVW: Byte = 0x0B;

/// Moves the specified value (SmallWord) to the specified register (Address)
/// ```
/// movs SMALLWORD, ADDRESS
/// ```
pub const MOVS: Byte = 0x0C;

/// Moves the specified value (TinyWord) to the specified register (Address)
/// ```
/// movt TINYWORD, ADDRESS
/// ```
pub const MOVT: Byte = 0x0D;

/// Moves the specified value (Byte) to the specified register (Address)
/// ```
/// movb BYTE, ADDRESS
/// ```
pub const MOVB: Byte = 0x0E;

/// Moves the value in the specified buffer register (Address) to the otherwise
/// specified buffer register (Address)
/// ```
/// mov ADDRESS, ADDRESS
/// ```
pub const MOV: Byte = 0x0F;

/// Moves the top most value of the data stack to the specified register
/// (Address)
/// ```
/// smov ADDRESS
/// ```
pub const SMOV: Byte = 0x10;

/// Registers an interrupt callback by mapping the specified signal_id to the
/// given function call address
/// ```
/// regi WORD, ADDRESS
/// ```
pub const REGI: Byte = 0x11;

/// Calls a function while pushing the return address to the return stack
/// ```
/// call ADDRESS
/// ```
pub const CALL: Byte = 0x12;

/// Returns from a function. The return value is pushed to the data stack
/// ```
/// ret
/// ```
pub const RET: Byte = 0x13;
<commit_msg>Added examples to bytecode definitions<commit_after>use typedef::*;

pub const PREAMBLE: &str = "BAKER1";

/// Stops the program and shuts down the vm
///
/// # Example
///
/// ```
/// halt
/// ```
pub const HALT: Byte = 0x01;

/// Adds the two top most values and pushes the result back to the data stack.
/// This also removes the processed values from the data stack.
///
/// # Example
///
/// ```
/// add
/// ```
pub const ADD: Byte = 0x02;

/// Subtracts the first value on the data stack from the second and pushes the
/// result back to the data stack. This also removes the processed values from
/// the data stack.
///
/// # Example
///
/// ```
/// sub
/// ```
pub const SUB: Byte = 0x03;

/// Adds the two top most values and pushes the result back to the data stack.
/// This also removes the processed values from the data stack.
///
/// # Example
///
/// ```
/// mul
/// ```
pub const MUL: Byte = 0x04;

/// Divides the second value on the data stack throuh the first one and pushes
/// the result back to the top of the data stack. This also removes the
/// processed values from the data stack.
///
/// # Example
///
/// ```
/// div
/// ```
pub const DIV: Byte = 0x05;

/// Prints out the top most value on the data stack
#[deprecated(since="0.1.0", note="will be replaced soon")]
pub const PRINT: Byte = 0x06;

/// Pushes a value (Word) to the data stack
///
/// # Example
///
/// ```
/// push WORD
/// ```
pub const PUSH: Byte = 0x07;

/// An unconditional jump to the specified address
///
/// # Example
///
/// ```
/// jmp ADDRESS
/// ```
pub const JMP: Byte = 0x08;

/// Jumps to the specified address if the top most value on the data stack
/// equals 0
///
/// # Example
///
/// ```
/// jz ADDRESS
/// ```
pub const JZ: Byte = 0x09;

/// Jumps to the specified address if the top most value on the data stack is
/// not equal to 0
///
/// # Example
///
/// ```
/// jnz ADDRESS
/// ```
pub const JNZ: Byte = 0x0A;

/// Moves the specified value (Word) to the specified register (Address)
///
/// # Example
///
/// ```
/// movw WORD, ADDRESS
/// ```
pub const MOVW: Byte = 0x0B;

/// Moves the specified value (SmallWord) to the specified register (Address)
///
/// # Example
///
/// ```
/// movs SMALLWORD, ADDRESS
/// ```
pub const MOVS: Byte = 0x0C;

/// Moves the specified value (TinyWord) to the specified register (Address)
///
/// # Example
///
/// ```
/// movt TINYWORD, ADDRESS
/// ```
pub const MOVT: Byte = 0x0D;

/// Moves the specified value (Byte) to the specified register (Address)
///
/// # Example
///
/// ```
/// movb BYTE, ADDRESS
/// ```
pub const MOVB: Byte = 0x0E;

/// Moves the value in the specified buffer register (Address) to the otherwise
/// specified buffer register (Address)
///
/// # Example
///
/// ```
/// mov ADDRESS, ADDRESS
/// ```
pub const MOV: Byte = 0x0F;

/// Moves the top most value of the data stack to the specified register
/// (Address)
///
/// # Example
///
/// ```
/// smov ADDRESS
/// ```
pub const SMOV: Byte = 0x10;

/// Registers an interrupt callback by mapping the specified signal_id to the
/// given function call address
///
/// # Example
///
/// ```
/// regi WORD, ADDRESS
/// ```
pub const REGI: Byte = 0x11;

/// Calls a function while pushing the return address to the return stack
///
/// # Example
///
/// ```
/// call ADDRESS
/// ```
pub const CALL: Byte = 0x12;

/// Returns from a function. The return value is pushed to the data stack
///
/// # Example
///
/// ```
/// ret
/// ```
pub const RET: Byte = 0x13;
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use collections::string::String;

use common::event;

use drivers::io::{Io, Pio};

use fs::KScheme;

#[repr(packed)]
struct SerialInfo {
    pub ports: [u16; 4],
}

const SERIALINFO: *const SerialInfo = 0x400 as *const SerialInfo;

/// Serial
pub struct Serial {
    pub data: Pio<u8>,
    pub status: Pio<u8>,
    pub irq: u8,
    pub escape: bool,
    pub cursor_control: bool,
}

impl Serial {
    /// Create new
    pub fn new(port: u16, irq: u8) -> Box<Self> {
        Pio::<u8>::new(port + 1).write(0x00);
        Pio::<u8>::new(port + 3).write(0x80);
        Pio::<u8>::new(port + 0).write(0x03);
        Pio::<u8>::new(port + 1).write(0x00);
        Pio::<u8>::new(port + 3).write(0x03);
        Pio::<u8>::new(port + 2).write(0xC7);
        Pio::<u8>::new(port + 4).write(0x0B);
        Pio::<u8>::new(port + 1).write(0x01);

        box Serial {
            data: Pio::<u8>::new(port),
            status: Pio::<u8>::new(port + 5),
            irq: irq,
            escape: false,
            cursor_control: false,
        }
    }
}

impl KScheme for Serial {
    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            while self.status.read() & 1 == 0 {}

            let mut c = self.data.read() as char;
            let mut sc = 0;

            if self.escape {
                self.escape = false;

                if c == '[' {
                    self.cursor_control = true;
                }

                c = '\0';
            } else if self.cursor_control {
                self.cursor_control = false;

                c = '\0';

                if c == 'A' {
                    sc = event::K_UP;
                } else if c == 'B' {
                    sc = event::K_DOWN;
                } else if c == 'C' {
                    sc = event::K_RIGHT;
                } else if c == 'D' {
                    sc = event::K_LEFT;
                }
            } else if c == '\x03' {
                ::env().console.lock().write(b"^C\n");
                ::env().console.lock().commands.send(String::new());

                c = '\0';
                sc = 0;
            } else if c == '\x1B' {
                self.escape = true;
                c = '\0';
            } else if c == '\r' {
                c = '\n';
            } else if c == '\x7F' {
                c = '\0';
                sc = event::K_BKSP;
            }

            if c != '\0' || sc != 0 {
                let key_event = event::KeyEvent {
                    character: c,
                    scancode: sc,
                    pressed: true,
                };

                ::env().console.lock().event(key_event.to_event());
            }
        }
    }
}
<commit_msg>Lock console once<commit_after>use alloc::boxed::Box;

use collections::string::String;

use common::event;

use drivers::io::{Io, Pio};

use fs::KScheme;

#[repr(packed)]
struct SerialInfo {
    pub ports: [u16; 4],
}

const SERIALINFO: *const SerialInfo = 0x400 as *const SerialInfo;

/// Serial
pub struct Serial {
    pub data: Pio<u8>,
    pub status: Pio<u8>,
    pub irq: u8,
    pub escape: bool,
    pub cursor_control: bool,
}

impl Serial {
    /// Create new
    pub fn new(port: u16, irq: u8) -> Box<Self> {
        Pio::<u8>::new(port + 1).write(0x00);
        Pio::<u8>::new(port + 3).write(0x80);
        Pio::<u8>::new(port + 0).write(0x03);
        Pio::<u8>::new(port + 1).write(0x00);
        Pio::<u8>::new(port + 3).write(0x03);
        Pio::<u8>::new(port + 2).write(0xC7);
        Pio::<u8>::new(port + 4).write(0x0B);
        Pio::<u8>::new(port + 1).write(0x01);

        box Serial {
            data: Pio::<u8>::new(port),
            status: Pio::<u8>::new(port + 5),
            irq: irq,
            escape: false,
            cursor_control: false,
        }
    }
}

impl KScheme for Serial {
    fn on_irq(&mut self, irq: u8) {
        if irq == self.irq {
            while self.status.read() & 1 == 0 {}

            let mut c = self.data.read() as char;
            let mut sc = 0;

            let mut console = ::env().console.lock();

            if self.escape {
                self.escape = false;

                if c == '[' {
                    self.cursor_control = true;
                }

                c = '\0';
            } else if self.cursor_control {
                self.cursor_control = false;

                c = '\0';

                if c == 'A' {
                    sc = event::K_UP;
                } else if c == 'B' {
                    sc = event::K_DOWN;
                } else if c == 'C' {
                    sc = event::K_RIGHT;
                } else if c == 'D' {
                    sc = event::K_LEFT;
                }
            } else if c == '\x03' {
                console.write(b"^C\n");
                console.commands.send(String::new());

                c = '\0';
                sc = 0;
            } else if c == '\x1B' {
                self.escape = true;
                c = '\0';
            } else if c == '\r' {
                c = '\n';
            } else if c == '\x7F' {
                c = '\0';
                sc = event::K_BKSP;
            }

            if c != '\0' || sc != 0 {
                let key_event = event::KeyEvent {
                    character: c,
                    scancode: sc,
                    pressed: true,
                };

                console.event(key_event.to_event());
            }
        }
    }
}
<|endoftext|>