<commit_before>use std::collections::{VecDeque, HashMap};

use memory::{StaticAllocator, MemoryBlock};

use super::item_type::ItemType;

/// Represents a single item in a scope
pub struct ScopeItem {
    type_def: ItemType,
    memory: MemoryBlock,
}

/// Represents a single level of scope
pub type Scope = HashMap<String, ScopeItem>;

pub struct ScopeStack {
    stack: VecDeque<Scope>,
    allocator: StaticAllocator,
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack {
            stack: {
                let mut queue = VecDeque::new();
                queue.push_back(Scope::new());
                queue
            },
            allocator: StaticAllocator::new(),
        }
    }

    /// Pushes a new level of scope onto the stack
    /// This scope will become the current scope
    pub fn push_scope(&mut self) {
        self.stack.push_back(Scope::new());
    }

    /// Removes and returns the top level scope (current scope)
    ///
    /// # Panics
    /// Panics if there is no scope in the stack
    pub fn pop_scope(&mut self) -> Scope {
        self.stack.pop_back().unwrap()
    }

    /// Looks up a name starting at the current scope
    /// Returns ALL matches so that the caller can determine which definition is
    /// the correct one
    /// Definitions are returned in order from latest definition to oldest
    /// Always use the first definition that matches the type you are looking for
    pub fn lookup(&self, name: &str) -> Vec<&ScopeItem> {
        self.stack.iter().rev().map(|sc| sc.get(name)).fold(Vec::new(), |mut acc, r| match r {
            Some(def) => {
                acc.push(def);
                acc
            },
            None => acc,
        })
    }

    /// Declares a name with the given type, allocates enough space for that type
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    pub fn declare(&mut self, name: String, typ: &ItemType) -> MemoryBlock {
        let mem = self.allocate(typ);
        // It's OK to overwrite existing names because we support rebinding
        if let Some(scope) = self.stack.back_mut() {
            scope.insert(name, ScopeItem {
                type_def: typ.clone(),
                memory: mem,
            });
        }
        else {
            panic!("Attempt to declare name despite having no current scope");
        }

        mem
    }

    /// Allocate a memory block that is large enough for the given type
    /// Does not associate memory block with a name which means it cannot be looked up later
    /// Returns the allocated memory block
    pub fn allocate(&mut self, typ: &ItemType) -> MemoryBlock {
        let size = typ.required_size(self);
        self.allocator.allocate(size)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn multiple_definitions() {
        let mut scope = ScopeStack::new();
        assert_eq!(scope.lookup("foo").len(), 0);

        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 1);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 1);

        scope.push_scope();
        // Declaring foo in another scope should add a definition
        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 2);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 2);
    }
}
<commit_msg>Implemented function on scope for easily adding built-in functions<commit_after>use std::rc::Rc;
use std::collections::{VecDeque, HashMap};

use memory::{StaticAllocator, MemoryBlock};

use super::operation::Operation;
use super::item_type::{ItemType, FunctionTypeDef, FuncArgs};

/// Represents a single item in a scope
pub struct ScopeItem {
    type_def: ItemType,
    memory: MemoryBlock,
}

/// Represents a single level of scope
pub type Scope = HashMap<String, ScopeItem>;

pub struct ScopeStack {
    stack: VecDeque<Scope>,
    allocator: StaticAllocator,
}

impl ScopeStack {
    pub fn new() -> ScopeStack {
        ScopeStack {
            stack: {
                let mut queue = VecDeque::new();
                queue.push_back(Scope::new());
                queue
            },
            allocator: StaticAllocator::new(),
        }
    }

    /// Pushes a new level of scope onto the stack
    /// This scope will become the current scope
    pub fn push_scope(&mut self) {
        self.stack.push_back(Scope::new());
    }

    /// Removes and returns the top level scope (current scope)
    ///
    /// # Panics
    /// Panics if there is no scope in the stack
    pub fn pop_scope(&mut self) -> Scope {
        self.stack.pop_back().unwrap()
    }

    /// Looks up a name starting at the current scope
    /// Returns ALL matches so that the caller can determine which definition is
    /// the correct one
    /// Definitions are returned in order from latest definition to oldest
    /// Always use the first definition that matches the type you are looking for
    pub fn lookup(&self, name: &str) -> Vec<&ScopeItem> {
        self.stack.iter().rev().map(|sc| sc.get(name)).fold(Vec::new(), |mut acc, r| match r {
            Some(def) => {
                acc.push(def);
                acc
            },
            None => acc,
        })
    }

    /// Declares a name with the given type, allocates enough space for that type
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    pub fn declare(&mut self, name: String, typ: &ItemType) -> MemoryBlock {
        let mem = self.allocate(typ);
        // It's OK to overwrite existing names because we support rebinding
        if let Some(scope) = self.stack.back_mut() {
            scope.insert(name, ScopeItem {
                type_def: typ.clone(),
                memory: mem,
            });
        }
        else {
            panic!("Attempt to declare name despite having no current scope");
        }

        mem
    }

    /// Declares a built in function with the given name and type definition
    /// The name is declared in the "current" scope which is at the top of the stack
    /// Returns the allocated memory block
    fn declare_builtin_function<F: 'static>(&mut self, name: String, func_type: FunctionTypeDef, f: F) -> MemoryBlock
        where F: Fn(FuncArgs, ScopeStack) -> Vec<Operation> {

        self.declare(
            name,
            &ItemType::BuiltInFunction {
                type_def: func_type,
                operations: Rc::new(f),
            }
        )
    }

    /// Allocate a memory block that is large enough for the given type
    /// Does not associate memory block with a name which means it cannot be looked up later
    /// Returns the allocated memory block
    pub fn allocate(&mut self, typ: &ItemType) -> MemoryBlock {
        let size = typ.required_size(self);
        self.allocator.allocate(size)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn multiple_definitions() {
        let mut scope = ScopeStack::new();
        assert_eq!(scope.lookup("foo").len(), 0);

        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 1);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 1);

        scope.push_scope();
        // Declaring foo in another scope should add a definition
        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 2);

        // Declaring the same name in the same scope should overwrite the
        // definition
        scope.declare("foo".to_owned(), unimplemented!());
        assert_eq!(scope.lookup("foo").len(), 2);
    }
}
<|endoftext|>


<commit_before>use bot::BotEnv;
use commands::*;
use listeners::{Timeouts, PollTagger, AutoReplyListener, ReactionAuthorize, Log};

use lalafell::listeners::CommandListener;

use serenity::prelude::RwLock;
use serenity::model::prelude::*;
use serenity::client::{EventHandler, Context};
use serenity::client::bridge::gateway::event::ShardStageUpdateEvent;

use serde_json::Value;

use std::sync::Arc;
use std::collections::HashMap;

pub struct Handler {
  env: Arc<BotEnv>,
  listeners: Vec<Box<EventHandler + Send + Sync>>
}

impl Handler {
  pub fn new(env: Arc<BotEnv>) -> Self {
    let listeners: Vec<Box<EventHandler + Send + Sync>> = vec![
      box command_listener(&env),
      box ReactionAuthorize,
      box Timeouts,
      box PollTagger,
      box AutoReplyListener::default(),
      box Log::new(env.clone())
    ];
    Handler {
      env,
      listeners
    }
  }
}

macro_rules! handler {
  ($name:ident, $($param:ident: $kind:ty),+) => {
    fn $name(&self, $($param: $kind),+) {
      for listener in &self.listeners {
        listener.$name($($param.clone()),+);
      }
    }
  }
}

impl EventHandler for Handler {
  handler!(cached, param1: Context, param2: Vec < GuildId >);
  handler!(category_create, param1: Context, param2: Arc < RwLock < ChannelCategory > >);
  handler!(category_delete, param1: Context, param2: Arc < RwLock < ChannelCategory > >);
  handler!(channel_create, param1: Context, param2: Arc < RwLock < GuildChannel > >);
  handler!(channel_delete, param1: Context, param2: Arc < RwLock < GuildChannel > >);
  handler!(channel_pins_update, param1: Context, param2: ChannelPinsUpdateEvent);
  handler!(channel_recipient_addition, param1: Context, param2: ChannelId, param3: User);
  handler!(channel_recipient_removal, param1: Context, param2: ChannelId, param3: User);
  handler!(channel_update, param1: Context, param2: Option < Channel >, param3: Channel);
  handler!(guild_ban_addition, param1: Context, param2: GuildId, param3: User);
  handler!(guild_ban_removal, param1: Context, param2: GuildId, param3: User);
  handler!(guild_create, param1: Context, param2: Guild, param3: bool);
  handler!(guild_delete, param1: Context, param2: PartialGuild, param3: Option < Arc < RwLock < Guild > > >);
  handler!(guild_emojis_update, param1: Context, param2: GuildId, param3: HashMap < EmojiId , Emoji >);
  handler!(guild_integrations_update, param1: Context, param2: GuildId);
  handler!(guild_member_addition, param1: Context, param2: GuildId, param3: Member);
  handler!(guild_member_removal, param1: Context, param2: GuildId, param3: User, param4: Option < Member >);
  handler!(guild_member_update, param1: Context, param2: Option < Member >, param3: Member);
  handler!(guild_members_chunk, param1: Context, param2: GuildId, param3: HashMap < UserId , Member >);
  handler!(guild_role_create, param1: Context, param2: GuildId, param3: Role);
  handler!(guild_role_delete, param1: Context, param2: GuildId, param3: RoleId, param4: Option < Role >);
  handler!(guild_role_update, param1: Context, param2: GuildId, param3: Option < Role >, param4: Role);
  handler!(guild_unavailable, param1: Context, param2: GuildId);
  handler!(guild_update, param1: Context, param2: Option < Arc < RwLock < Guild > > >, param3: PartialGuild);
  handler!(message_delete_bulk, param1: Context, param2: ChannelId, param3: Vec < MessageId >);
  handler!(message_delete, param1: Context, param2: ChannelId, param3: MessageId);
  handler!(message_update, param1: Context, param2: MessageUpdateEvent);
  handler!(message, param1: Context, param2: Message);
  handler!(presence_replace, param1: Context, param2: Vec < Presence >);
  handler!(presence_update, param1: Context, param2: PresenceUpdateEvent);
  handler!(private_channel_create, param1: Context, param2: Arc < RwLock < PrivateChannel > >);
  handler!(reaction_add, param1: Context, param2: Reaction);
  handler!(reaction_remove_all, param1: Context, param2: ChannelId, param3: MessageId);
  handler!(reaction_remove, param1: Context, param2: Reaction);
  handler!(resume, param1: Context, param2: ResumedEvent);
  handler!(shard_stage_update, param1: Context, param2: ShardStageUpdateEvent);
  handler!(typing_start, param1: Context, param2: TypingStartEvent);
  handler!(unknown, param1: Context, param2: String, param3: Value);
  handler!(user_update, param1: Context, param2: CurrentUser, param3: CurrentUser);
  handler!(voice_server_update, param1: Context, param2: VoiceServerUpdateEvent);
  handler!(voice_state_update, param1: Context, param2: Option < GuildId >, param3: VoiceState);
  handler!(webhook_update, param1: Context, param2: GuildId, param3: ChannelId);

  fn ready(&self, ctx: Context, ready: Ready) {
    if let Some(g) = ::tasks::random_presence::random_game(self.env.as_ref()) {
      ctx.shard.set_game(Some(g));
    }
    for listener in &self.listeners {
      listener.ready(ctx.clone(), ready.clone());
    }
  }
}

macro_rules! command_listener {
  (env => $env:expr, $($($alias:expr),+ => $name:ident),+) => {{
    let mut command_listener = CommandListener::default();
    $(
      command_listener.add_command(&[$($alias),*], box $name::new(Arc::clone(&$env)));
    )*
    command_listener
  }}
}

fn command_listener<'a>(env: &Arc<BotEnv>) -> CommandListener<'a> {
  command_listener! {
    env => env,
    "archive" => ArchiveCommand,
    "autotag" => AutoTagCommand,
    "blob" => BlobCommand,
    "configure", "config" => ConfigureCommand,
    "imagedump", "dump" => ImageDumpCommand,
    "mention" => MentionCommand,
    "ping" => PingCommand,
    "poll" => PollCommand,
    "pollresults" => PollResultsCommand,
    "presence" => PresenceCommand,
    "race" => RaceCommand,
    "randomreaction", "reaction" => RandomReactionCommand,
    "referencecount" => ReferenceCountCommand,
    "reload", "reloadconfig" => ReloadConfigCommand,
    "search" => SearchCommand,
    "tag" => TagCommand,
    "timeout" => TimeoutCommand,
    "untimeout" => UntimeoutCommand,
    "updatetag" => UpdateTagCommand,
    "updatetags" => UpdateTagsCommand,
    "verify" => VerifyCommand,
    "viewtag" => ViewTagCommand
  }
}
<commit_msg>refactor: fix clippy suggestions<commit_after>use bot::BotEnv;
use commands::*;
use listeners::{Timeouts, PollTagger, AutoReplyListener, ReactionAuthorize, Log};

use lalafell::listeners::CommandListener;

use serenity::prelude::RwLock;
use serenity::model::prelude::*;
use serenity::client::{EventHandler, Context};
use serenity::client::bridge::gateway::event::ShardStageUpdateEvent;

use serde_json::Value;

use std::sync::Arc;
use std::collections::HashMap;

pub struct Handler {
  env: Arc<BotEnv>,
  listeners: Vec<Box<EventHandler + Send + Sync>>
}

impl Handler {
  pub fn new(env: Arc<BotEnv>) -> Self {
    let listeners: Vec<Box<EventHandler + Send + Sync>> = vec![
      box command_listener(&env),
      box ReactionAuthorize,
      box Timeouts,
      box PollTagger,
      box AutoReplyListener::default(),
      box Log::new(Arc::clone(&env))
    ];
    Handler {
      env,
      listeners
    }
  }
}

macro_rules! handler {
  ($name:ident, $($param:ident: $kind:ty),+) => {
    fn $name(&self, $($param: $kind),+) {
      for listener in &self.listeners {
        listener.$name($($param.clone()),+);
      }
    }
  }
}

impl EventHandler for Handler {
  handler!(cached, param1: Context, param2: Vec < GuildId >);
  handler!(category_create, param1: Context, param2: Arc < RwLock < ChannelCategory > >);
  handler!(category_delete, param1: Context, param2: Arc < RwLock < ChannelCategory > >);
  handler!(channel_create, param1: Context, param2: Arc < RwLock < GuildChannel > >);
  handler!(channel_delete, param1: Context, param2: Arc < RwLock < GuildChannel > >);
  handler!(channel_pins_update, param1: Context, param2: ChannelPinsUpdateEvent);
  handler!(channel_recipient_addition, param1: Context, param2: ChannelId, param3: User);
  handler!(channel_recipient_removal, param1: Context, param2: ChannelId, param3: User);
  handler!(channel_update, param1: Context, param2: Option < Channel >, param3: Channel);
  handler!(guild_ban_addition, param1: Context, param2: GuildId, param3: User);
  handler!(guild_ban_removal, param1: Context, param2: GuildId, param3: User);
  handler!(guild_create, param1: Context, param2: Guild, param3: bool);
  handler!(guild_delete, param1: Context, param2: PartialGuild, param3: Option < Arc < RwLock < Guild > > >);
  handler!(guild_emojis_update, param1: Context, param2: GuildId, param3: HashMap < EmojiId , Emoji >);
  handler!(guild_integrations_update, param1: Context, param2: GuildId);
  handler!(guild_member_addition, param1: Context, param2: GuildId, param3: Member);
  handler!(guild_member_removal, param1: Context, param2: GuildId, param3: User, param4: Option < Member >);
  handler!(guild_member_update, param1: Context, param2: Option < Member >, param3: Member);
  handler!(guild_members_chunk, param1: Context, param2: GuildId, param3: HashMap < UserId , Member >);
  handler!(guild_role_create, param1: Context, param2: GuildId, param3: Role);
  handler!(guild_role_delete, param1: Context, param2: GuildId, param3: RoleId, param4: Option < Role >);
  handler!(guild_role_update, param1: Context, param2: GuildId, param3: Option < Role >, param4: Role);
  handler!(guild_unavailable, param1: Context, param2: GuildId);
  handler!(guild_update, param1: Context, param2: Option < Arc < RwLock < Guild > > >, param3: PartialGuild);
  handler!(message_delete_bulk, param1: Context, param2: ChannelId, param3: Vec < MessageId >);
  handler!(message_delete, param1: Context, param2: ChannelId, param3: MessageId);
  handler!(message_update, param1: Context, param2: MessageUpdateEvent);
  handler!(message, param1: Context, param2: Message);
  handler!(presence_replace, param1: Context, param2: Vec < Presence >);
  handler!(presence_update, param1: Context, param2: PresenceUpdateEvent);
  handler!(private_channel_create, param1: Context, param2: Arc < RwLock < PrivateChannel > >);
  handler!(reaction_add, param1: Context, param2: Reaction);
  handler!(reaction_remove_all, param1: Context, param2: ChannelId, param3: MessageId);
  handler!(reaction_remove, param1: Context, param2: Reaction);
  handler!(resume, param1: Context, param2: ResumedEvent);
  handler!(shard_stage_update, param1: Context, param2: ShardStageUpdateEvent);
  handler!(typing_start, param1: Context, param2: TypingStartEvent);
  handler!(unknown, param1: Context, param2: String, param3: Value);
  handler!(user_update, param1: Context, param2: CurrentUser, param3: CurrentUser);
  handler!(voice_server_update, param1: Context, param2: VoiceServerUpdateEvent);
  handler!(voice_state_update, param1: Context, param2: Option < GuildId >, param3: VoiceState);
  handler!(webhook_update, param1: Context, param2: GuildId, param3: ChannelId);

  fn ready(&self, ctx: Context, ready: Ready) {
    if let Some(g) = ::tasks::random_presence::random_game(self.env.as_ref()) {
      ctx.shard.set_game(Some(g));
    }
    for listener in &self.listeners {
      listener.ready(ctx.clone(), ready.clone());
    }
  }
}

macro_rules! command_listener {
  (env => $env:expr, $($($alias:expr),+ => $name:ident),+) => {{
    let mut command_listener = CommandListener::default();
    $(
      command_listener.add_command(&[$($alias),*], box $name::new(Arc::clone($env)));
    )*
    command_listener
  }}
}

fn command_listener<'a>(env: &Arc<BotEnv>) -> CommandListener<'a> {
  command_listener! {
    env => env,
    "archive" => ArchiveCommand,
    "autotag" => AutoTagCommand,
    "blob" => BlobCommand,
    "configure", "config" => ConfigureCommand,
    "imagedump", "dump" => ImageDumpCommand,
    "mention" => MentionCommand,
    "ping" => PingCommand,
    "poll" => PollCommand,
    "pollresults" => PollResultsCommand,
    "presence" => PresenceCommand,
    "race" => RaceCommand,
    "randomreaction", "reaction" => RandomReactionCommand,
    "referencecount" => ReferenceCountCommand,
    "reload", "reloadconfig" => ReloadConfigCommand,
    "search" => SearchCommand,
    "tag" => TagCommand,
    "timeout" => TimeoutCommand,
    "untimeout" => UntimeoutCommand,
    "updatetag" => UpdateTagCommand,
    "updatetags" => UpdateTagsCommand,
    "verify" => VerifyCommand,
    "viewtag" => ViewTagCommand
  }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::hash::Hash;
use std::fmt;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};

use serde::ser::{Serialize, Serializer, SerializeMap};
use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess};

use intern::{LatticeKey as Key, LatticeVar as Var, SessionId};
use metrics::{Integer};

lazy_static! {
    pub static ref SHARED_KEYS: Integer = Integer::new();
    pub static ref SHARED_COUNTERS: Integer = Integer::new();
    pub static ref SHARED_SETS: Integer = Integer::new();
    pub static ref PRIVATE_KEYS: Integer = Integer::new();
    pub static ref PRIVATE_COUNTERS: Integer = Integer::new();
    pub static ref PRIVATE_SETS: Integer = Integer::new();
    pub static ref SET_ITEMS: Integer = Integer::new();
}

#[derive(Debug, Clone)]
pub struct Counter(u64);
// TODO(tailhook) implement some persistent hash set
// TODO(tailhook) optimize set of only int-like values
#[derive(Debug, Clone)]
pub struct Set(Arc<HashSet<String>>);

trait Crdt: Clone + Sized {
    /// Updates returning `true` if value changed
    fn update(&mut self, other: &Self) -> bool;
}

#[derive(Debug, Clone)]
pub struct Values {
    counters: HashMap<Var, Counter>,
    sets: HashMap<Var, Set>,
}

pub struct Lattice {
    pub shared: HashMap<Key, Values>,
    pub private: HashMap<SessionId, HashMap<Key, Values>>,
    pub subscriptions: HashMap<Key, HashSet<SessionId>>,
}

#[derive(Debug, Clone, Serialize)]
pub struct Delta {
    pub shared: HashMap<Key, Values>,
    pub private: HashMap<SessionId, HashMap<Key, Values>>,
}

impl Values {
    pub fn new() -> Values {
        Values {
            counters: HashMap::new(),
            sets: HashMap::new(),
        }
    }
    pub fn update(&mut self, other: &Values) {
        for (key, value) in &other.counters {
            self.counters.insert(key.clone(), value.clone());
        }
        for (key, value) in &other.sets {
            self.sets.insert(key.clone(), value.clone());
        }
    }
    pub fn is_empty(&self) -> bool {
        self.counters.len() == 0 && self.sets.len() == 0
    }
}

impl Serialize for Values {
    fn serialize<S: Serializer>(&self, serialize: S)
        -> Result<S::Ok, S::Error>
    {
        let mut map = serialize.serialize_map(
            Some(self.counters.len() + self.sets.len()))?;
        for (k, counter) in &self.counters {
            map.serialize_key(&format!("{}_counter", k))?;
            map.serialize_value(&counter.0)?;
        }
        for (k, set) in &self.sets {
            map.serialize_key(&format!("{}_set", k))?;
            map.serialize_value(&set.0)?;
        }
        map.end()
    }
}

impl Lattice {
    pub fn new() -> Lattice {
        Lattice {
            shared: HashMap::new(),
            private: HashMap::new(),
            subscriptions: HashMap::new(),
        }
    }
    /// Updates lattice to be up to date with Delta and returns modified delta
    /// that contains only data that really changed and not out of date
    pub fn update(&mut self, mut delta: Delta) -> Delta {
        let mut del = Vec::new();
        for (room, values) in &mut delta.shared {
            let mine = self.shared.entry(room.clone())
                        .or_insert_with(|| {
                            SHARED_KEYS.incr(1);
                            Values::new()
                        });

            crdt_update(&mut mine.counters, &mut values.counters,
                &*SHARED_COUNTERS);
            crdt_update(&mut mine.sets, &mut values.sets,
                &*SHARED_SETS);

            if values.is_empty() {
                del.push(room.clone());
            }
        }
        for key in &del {
            delta.shared.remove(key);
        }

        for (session_id, rooms) in &mut delta.private {
            let mysess = self.private.entry(session_id.clone())
                .or_insert_with(HashMap::new);
            let mut del_rooms = Vec::new();
            for (room, values) in rooms.iter_mut() {
                let mine = mysess.entry(room.clone())
                    .or_insert_with(|| {
                        PRIVATE_KEYS.incr(1);
                        Values::new()
                    });

                crdt_update(&mut mine.counters, &mut values.counters,
                    &*PRIVATE_COUNTERS);
                crdt_update(&mut mine.sets, &mut values.sets,
                    &*PRIVATE_SETS);

                if values.is_empty() {
                    del_rooms.push(room.clone());
                }
            }
            for key in &del_rooms {
                if rooms.remove(key).is_some() {
                    PRIVATE_KEYS.decr(1);
                }
            }
        }
        return delta
    }

    pub fn remove_session(&mut self, sid: &SessionId) {
        if let Some(skeys) = self.private.remove(sid) {
            for (key, value) in skeys {
                if let Occupied(mut subs) = self.subscriptions.entry(key.clone()) {
                    subs.get_mut().remove(sid);
                    if subs.get().is_empty() {
                        subs.remove_entry();
                        if self.shared.remove(&key).is_some() {
                            SHARED_KEYS.decr(1);
                        }
                    }
                } else {
                    error!("Subscription inconsistency {:?} {:?}", sid, key);
                }
            }
        }
    }

    pub fn is_empty(&self) -> bool {
        self.shared.is_empty()
        && self.private.is_empty()
        && self.subscriptions.is_empty()
    }
}

impl Crdt for Counter {
    fn update(&mut self, other: &Self) -> bool {
        if self.0 < other.0 {
            self.0 = other.0;
            true
        } else {
            false
        }
    }
}

impl Crdt for Set {
    fn update(&mut self, other: &Self) -> bool {
        let mut iter = other.0.iter();
        let ref mut arc = self.0;
        while let Some(key) = iter.next() {
            if !arc.contains(key) {
                let nset = Arc::make_mut(arc);
                if nset.insert(key.clone()) {
                    SET_ITEMS.incr(1);
                }
                for item in iter {
                    if nset.insert(item.clone()) {
                        SET_ITEMS.incr(1);
                    }
                }
                return true;
            }
        }
        return false;
    }
}

fn crdt_update<K, V>(original: &mut HashMap<K, V>, delta: &mut HashMap<K, V>,
    number: &Integer)
    where K: Clone + Hash + Eq + ::std::fmt::Debug, V: Crdt
{
    let mut del = Vec::new();
    for (key, crdt) in delta {
        match original.entry(key.clone()) {
            Occupied(mut entry) => {
                if !entry.get_mut().update(crdt) {
                    del.push(key.clone());
                }
            }
            Vacant(entry) => {
                number.incr(1);
                entry.insert(crdt.clone());
            }
        }
    }
    for key in &del {
        if original.remove(key).is_some() {
            number.decr(1);
        }
    }
}

impl<'de> Deserialize<'de> for Delta {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        #[derive(Deserialize)]
        struct DeltaOpt {
            pub shared: Option<HashMap<Key, Values>>,
            pub private: Option<HashMap<SessionId, HashMap<Key, Values>>>,
        }
        let tmp = DeltaOpt::deserialize(deserializer)?;
        Ok(Delta {
            shared: tmp.shared.unwrap_or_else(HashMap::new),
            private: tmp.private.unwrap_or_else(HashMap::new),
        })
    }
}

struct ValuesVisitor;

impl<'de> Visitor<'de> for ValuesVisitor {
    type Value = Values;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("map expected")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
        where M: MapAccess<'de>
    {
        let mut values = Values {
            counters: HashMap::new(),
            sets: HashMap::new(),
        };
        while let Some(key) = access.next_key::<&str>()? {
            if key.ends_with("_counter") {
                let val = access.next_value()?;
                let key = key[..key.len() - "_counter".len()].parse()
                    .map_err(de::Error::custom)?;
                values.counters.insert(key, Counter(val));
            } else if key.ends_with("_set") {
                let val = access.next_value()?;
                let key = key[..key.len() - "_set".len()].parse()
                    .map_err(de::Error::custom)?;
                values.sets.insert(key, val);
            } else {
                return Err(de::Error::custom(format!(
                    "Unsupported key {:?}", key)))
            }
        }
        Ok(values)
    }
}

impl<'de> Deserialize<'de> for Values {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_map(ValuesVisitor)
    }
}

impl<'de> Deserialize<'de> for Set {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        Ok(Set(Deserialize::deserialize(deserializer)?))
    }
}

#[cfg(test)]
mod test {
    use std::str::FromStr;
    use serde_json::from_str as json_decode;

    use super::{Delta, Values, Set};
    use intern::{LatticeKey as Key, LatticeVar as Var};

    #[test]
    fn decode_delta() {
        let val = r#"{"shared": {"room_1": {"last_message_counter": 125}},
            "private": {"user:1": {"room_1": {
                "last_seen_set": ["123", "124"]
            }}}}"#;

        let delta: Delta = json_decode(val).unwrap();
        assert_eq!(delta.shared.len(), 1);
        assert_eq!(delta.private.len(), 1);
        assert!(delta.shared.contains_key(&Key::from_str("room_1").unwrap()));
    }

    #[test]
    fn decode_values() {
        let val = r#"{"last_message_counter": 123}"#;
        let val: Values = json_decode(val).unwrap();
        assert_eq!(val.counters.len(), 1);
        assert_eq!(val.sets.len(), 0);

        let key = Var::from_str("last_message").unwrap();
        assert!(val.counters.contains_key(&key));
        assert_eq!(val.counters.get(&key).unwrap().0, 123u64);
    }

    #[test]
    fn decode_set() {
        let set: Set = json_decode(r#"["123", "123", "abc"]"#).unwrap();
        assert_eq!(set.0.len(), 2);
    }
}
<commit_msg>Fixes private keys counter<commit_after>use std::sync::Arc;
use std::hash::Hash;
use std::fmt;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};

use serde::ser::{Serialize, Serializer, SerializeMap};
use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess};

use intern::{LatticeKey as Key, LatticeVar as Var, SessionId};
use metrics::{Integer};

lazy_static! {
    pub static ref SHARED_KEYS: Integer = Integer::new();
    pub static ref SHARED_COUNTERS: Integer = Integer::new();
    pub static ref SHARED_SETS: Integer = Integer::new();
    pub static ref PRIVATE_KEYS: Integer = Integer::new();
    pub static ref PRIVATE_COUNTERS: Integer = Integer::new();
    pub static ref PRIVATE_SETS: Integer = Integer::new();
    pub static ref SET_ITEMS: Integer = Integer::new();
}

#[derive(Debug, Clone)]
pub struct Counter(u64);
// TODO(tailhook) implement some persistent hash set
// TODO(tailhook) optimize set of only int-like values
#[derive(Debug, Clone)]
pub struct Set(Arc<HashSet<String>>);

trait Crdt: Clone + Sized {
    /// Updates returning `true` if value changed
    fn update(&mut self, other: &Self) -> bool;
}

#[derive(Debug, Clone)]
pub struct Values {
    counters: HashMap<Var, Counter>,
    sets: HashMap<Var, Set>,
}

pub struct Lattice {
    pub shared: HashMap<Key, Values>,
    pub private: HashMap<SessionId, HashMap<Key, Values>>,
    pub subscriptions: HashMap<Key, HashSet<SessionId>>,
}

#[derive(Debug, Clone, Serialize)]
pub struct Delta {
    pub shared: HashMap<Key, Values>,
    pub private: HashMap<SessionId, HashMap<Key, Values>>,
}

impl Values {
    pub fn new() -> Values {
        Values {
            counters: HashMap::new(),
            sets: HashMap::new(),
        }
    }
    pub fn update(&mut self, other: &Values) {
        for (key, value) in &other.counters {
            self.counters.insert(key.clone(), value.clone());
        }
        for (key, value) in &other.sets {
            self.sets.insert(key.clone(), value.clone());
        }
    }
    pub fn is_empty(&self) -> bool {
        self.counters.len() == 0 && self.sets.len() == 0
    }
}

impl Serialize for Values {
    fn serialize<S: Serializer>(&self, serialize: S)
        -> Result<S::Ok, S::Error>
    {
        let mut map = serialize.serialize_map(
            Some(self.counters.len() + self.sets.len()))?;
        for (k, counter) in &self.counters {
            map.serialize_key(&format!("{}_counter", k))?;
            map.serialize_value(&counter.0)?;
        }
        for (k, set) in &self.sets {
            map.serialize_key(&format!("{}_set", k))?;
            map.serialize_value(&set.0)?;
        }
        map.end()
    }
}

impl Lattice {
    pub fn new() -> Lattice {
        Lattice {
            shared: HashMap::new(),
            private: HashMap::new(),
            subscriptions: HashMap::new(),
        }
    }
    /// Updates lattice to be up to date with Delta and returns modified delta
    /// that contains only data that really changed and not out of date
    pub fn update(&mut self, mut delta: Delta) -> Delta {
        let mut del = Vec::new();
        for (room, values) in &mut delta.shared {
            let mine = self.shared.entry(room.clone())
                        .or_insert_with(|| {
                            SHARED_KEYS.incr(1);
                            Values::new()
                        });

            crdt_update(&mut mine.counters, &mut values.counters,
                &*SHARED_COUNTERS);
            crdt_update(&mut mine.sets, &mut values.sets,
                &*SHARED_SETS);

            if values.is_empty() {
                del.push(room.clone());
            }
        }
        for key in &del {
            delta.shared.remove(key);
        }

        for (session_id, rooms) in &mut delta.private {
            let mysess = self.private.entry(session_id.clone())
                .or_insert_with(HashMap::new);
            let mut del_rooms = Vec::new();
            for (room, values) in rooms.iter_mut() {
                let mine = mysess.entry(room.clone())
                    .or_insert_with(|| {
                        PRIVATE_KEYS.incr(1);
                        Values::new()
                    });

                crdt_update(&mut mine.counters, &mut values.counters,
                    &*PRIVATE_COUNTERS);
                crdt_update(&mut mine.sets, &mut values.sets,
                    &*PRIVATE_SETS);

                if values.is_empty() {
                    del_rooms.push(room.clone());
                }
            }
            for key in &del_rooms {
                rooms.remove(key);
            }
        }
        return delta
    }

    pub fn remove_session(&mut self, sid: &SessionId) {
        if let Some(skeys) = self.private.remove(sid) {
            PRIVATE_KEYS.decr(skeys.len() as i64);
            for (key, value) in skeys {
                if let Occupied(mut subs) = self.subscriptions.entry(key.clone()) {
                    subs.get_mut().remove(sid);
                    if subs.get().is_empty() {
                        subs.remove_entry();
                        if self.shared.remove(&key).is_some() {
                            SHARED_KEYS.decr(1);
                        }
                    }
                } else {
                    error!("Subscription inconsistency {:?} {:?}", sid, key);
                }
            }
        }
    }

    pub fn is_empty(&self) -> bool {
        self.shared.is_empty()
        && self.private.is_empty()
        && self.subscriptions.is_empty()
    }
}

impl Crdt for Counter {
    fn update(&mut self, other: &Self) -> bool {
        if self.0 < other.0 {
            self.0 = other.0;
            true
        } else {
            false
        }
    }
}

impl Crdt for Set {
    fn update(&mut self, other: &Self) -> bool {
        let mut iter = other.0.iter();
        let ref mut arc = self.0;
        while let Some(key) = iter.next() {
            if !arc.contains(key) {
                let nset = Arc::make_mut(arc);
                if nset.insert(key.clone()) {
                    SET_ITEMS.incr(1);
                }
                for item in iter {
                    if nset.insert(item.clone()) {
                        SET_ITEMS.incr(1);
                    }
                }
                return true;
            }
        }
        return false;
    }
}

fn crdt_update<K, V>(original: &mut HashMap<K, V>, delta: &mut HashMap<K, V>,
    number: &Integer)
    where K: Clone + Hash + Eq + ::std::fmt::Debug, V: Crdt
{
    let mut del = Vec::new();
    for (key, crdt) in delta {
        match original.entry(key.clone()) {
            Occupied(mut entry) => {
                if !entry.get_mut().update(crdt) {
                    del.push(key.clone());
                }
            }
            Vacant(entry) => {
                number.incr(1);
                entry.insert(crdt.clone());
            }
        }
    }
    for key in &del {
        if original.remove(key).is_some() {
            number.decr(1);
        }
    }
}

impl<'de> Deserialize<'de> for Delta {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        #[derive(Deserialize)]
        struct DeltaOpt {
            pub shared: Option<HashMap<Key, Values>>,
            pub private: Option<HashMap<SessionId, HashMap<Key, Values>>>,
        }
        let tmp = DeltaOpt::deserialize(deserializer)?;
        Ok(Delta {
            shared: tmp.shared.unwrap_or_else(HashMap::new),
            private: tmp.private.unwrap_or_else(HashMap::new),
        })
    }
}

struct ValuesVisitor;

impl<'de> Visitor<'de> for ValuesVisitor {
    type Value = Values;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("map expected")
    }

    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
        where M: MapAccess<'de>
    {
        let mut values = Values {
            counters: HashMap::new(),
            sets: HashMap::new(),
        };
        while let Some(key) = access.next_key::<&str>()? {
            if key.ends_with("_counter") {
                let val = access.next_value()?;
                let key = key[..key.len() - "_counter".len()].parse()
                    .map_err(de::Error::custom)?;
                values.counters.insert(key, Counter(val));
            } else if key.ends_with("_set") {
                let val = access.next_value()?;
                let key = key[..key.len() - "_set".len()].parse()
                    .map_err(de::Error::custom)?;
                values.sets.insert(key, val);
            } else {
                return Err(de::Error::custom(format!(
                    "Unsupported key {:?}", key)))
            }
        }
        Ok(values)
    }
}

impl<'de> Deserialize<'de> for Values {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        deserializer.deserialize_map(ValuesVisitor)
    }
}

impl<'de> Deserialize<'de> for Set {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        Ok(Set(Deserialize::deserialize(deserializer)?))
    }
}

#[cfg(test)]
mod test {
    use std::str::FromStr;
    use serde_json::from_str as json_decode;

    use super::{Delta, Values, Set};
    use intern::{LatticeKey as Key, LatticeVar as Var};

    #[test]
    fn decode_delta() {
        let val = r#"{"shared": {"room_1": {"last_message_counter": 125}},
            "private": {"user:1": {"room_1": {
                "last_seen_set": ["123", "124"]
            }}}}"#;

        let delta: Delta = json_decode(val).unwrap();
        assert_eq!(delta.shared.len(), 1);
        assert_eq!(delta.private.len(), 1);
        assert!(delta.shared.contains_key(&Key::from_str("room_1").unwrap()));
    }

    #[test]
    fn decode_values() {
        let val = r#"{"last_message_counter": 123}"#;
        let val: Values = json_decode(val).unwrap();
        assert_eq!(val.counters.len(), 1);
        assert_eq!(val.sets.len(), 0);

        let key = Var::from_str("last_message").unwrap();
        assert!(val.counters.contains_key(&key));
        assert_eq!(val.counters.get(&key).unwrap().0, 123u64);
    }

    #[test]
    fn decode_set() {
        let set: Set = json_decode(r#"["123", "123", "abc"]"#).unwrap();
        assert_eq!(set.0.len(), 2);
    }
}
<|endoftext|>


<commit_before>// You are likely to be eaten by a grue.

use std::{io, path, ptr, mem, ffi, slice, time};
use libc::{c_void, c_int, c_schar, c_uchar, size_t, uid_t, sysctl, sysctlnametomib, timeval};
use data::*;
use super::common::*;
use super::unix;
use super::bsd;

pub struct PlatformImpl;

macro_rules! sysctl_mib {
    ($len:expr, $name:expr) => {
        {
            let mut mib: [c_int; $len] = [0; $len];
            let mut sz: size_t = mib.len();
            let s = ffi::CString::new($name).unwrap();
            unsafe { sysctlnametomib(s.as_ptr(), &mut mib[0], &mut sz) };
            mib
        }
    }
}

macro_rules! sysctl {
    ($mib:expr, $dataptr:expr, $size:expr, $shouldcheck:expr) => {
        {
            let mib = &$mib;
            let mut size = $size;
            if unsafe { sysctl(&mib[0], mib.len() as u32,
                               $dataptr as *mut _ as *mut c_void, &mut size, ptr::null(), 0) } != 0 && $shouldcheck {
                return Err(io::Error::new(io::ErrorKind::Other, "sysctl() failed"))
            }
            size
        }
    };
    ($mib:expr, $dataptr:expr, $size:expr) => {
        sysctl!($mib, $dataptr, $size, true)
    }
}

lazy_static! {
    static ref KERN_CP_TIMES: [c_int; 2] = sysctl_mib!(2, "kern.cp_times");
    static ref KERN_BOOTTIME: [c_int; 2] = sysctl_mib!(2, "kern.boottime");
    static ref V_ACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_active_count");
    static ref V_INACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_inactive_count");
    static ref V_WIRE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_wire_count");
    static ref V_CACHE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_cache_count");
    static ref V_FREE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_free_count");
    static ref ZFS_ARC_SIZE: [c_int; 5] = sysctl_mib!(5, "kstat.zfs.misc.arcstats.size");
    static ref BATTERY_LIFE: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.life");
    static ref BATTERY_TIME: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.time");
    static ref ACLINE: [c_int; 3] = sysctl_mib!(3, "hw.acpi.acline");
    static ref CPU0TEMP: [c_int; 4] = sysctl_mib!(4, "dev.cpu.0.temperature");

    static ref CP_TIMES_SIZE: usize = {
        let mut size: usize = 0;
        unsafe { sysctl(&KERN_CP_TIMES[0], KERN_CP_TIMES.len() as u32,
                        ptr::null_mut(), &mut size, ptr::null(), 0) };
        size
    };
}

/// An implementation of `Platform` for FreeBSD.
/// See `Platform` for documentation.
impl Platform for PlatformImpl {
    #[inline(always)]
    fn new() -> Self {
        PlatformImpl
    }

    fn cpu_load(&self) -> io::Result<DelayedMeasurement<Vec<CPULoad>>> {
        let loads = try!(measure_cpu());
        Ok(DelayedMeasurement::new(
                Box::new(move || Ok(loads.iter()
                               .zip(try!(measure_cpu()).iter())
                               .map(|(prev, now)| (*now - prev).to_cpuload())
                               .collect::<Vec<_>>()))))
    }

    fn load_average(&self) -> io::Result<LoadAverage> {
        unix::load_average()
    }

    fn memory(&self) -> io::Result<Memory> {
        let mut active: usize = 0; sysctl!(V_ACTIVE_COUNT, &mut active, mem::size_of::<usize>());
        let mut inactive: usize = 0; sysctl!(V_INACTIVE_COUNT, &mut inactive, mem::size_of::<usize>());
        let mut wired: usize = 0; sysctl!(V_WIRE_COUNT, &mut wired, mem::size_of::<usize>());
        let mut cache: usize = 0; sysctl!(V_CACHE_COUNT, &mut cache, mem::size_of::<usize>(), false);
        let mut free: usize = 0; sysctl!(V_FREE_COUNT, &mut free, mem::size_of::<usize>());
        let arc = ByteSize::b(zfs_arc_size().unwrap_or(0));
        let pmem = PlatformMemory {
            active: ByteSize::kib(active << *bsd::PAGESHIFT),
            inactive: ByteSize::kib(inactive << *bsd::PAGESHIFT),
            wired: ByteSize::kib(wired << *bsd::PAGESHIFT) - arc,
            cache: ByteSize::kib(cache << *bsd::PAGESHIFT),
            zfs_arc: arc,
            free: ByteSize::kib(free << *bsd::PAGESHIFT),
        };
        Ok(Memory {
            total: pmem.active + pmem.inactive + pmem.wired + pmem.cache + arc + pmem.free,
            free: pmem.inactive + pmem.cache + arc + pmem.free,
            platform_memory: pmem,
        })
    }

    fn boot_time(&self) -> io::Result<DateTime<Utc>> {
        let mut data: timeval = unsafe { mem::zeroed() };
        sysctl!(KERN_BOOTTIME, &mut data, mem::size_of::<timeval>());
        Ok(DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(data.tv_sec.into(), data.tv_usec as u32), Utc))
    }

    fn battery_life(&self) -> io::Result<BatteryLife> {
        let mut life: usize = 0; sysctl!(BATTERY_LIFE, &mut life, mem::size_of::<usize>());
        let mut time: i32 = 0; sysctl!(BATTERY_TIME, &mut time, mem::size_of::<i32>());
        Ok(BatteryLife {
            remaining_capacity: life as f32 / 100.0,
            remaining_time: time::Duration::from_secs(if time < 0 { 0 } else { time as u64 }),
        })
    }

    fn on_ac_power(&self) -> io::Result<bool> {
        let mut on: usize = 0; sysctl!(ACLINE, &mut on, mem::size_of::<usize>());
        Ok(on == 1)
    }

    fn mounts(&self) -> io::Result<Vec<Filesystem>> {
        let mut mptr: *mut statfs = ptr::null_mut();
        let len = unsafe { getmntinfo(&mut mptr, 1 as i32) };
        if len < 1 {
            return Err(io::Error::new(io::ErrorKind::Other, "getmntinfo() failed"))
        }
        let mounts = unsafe { slice::from_raw_parts(mptr, len as usize) };
        Ok(mounts.iter().map(|m| m.to_fs()).collect::<Vec<_>>())
    }

    fn mount_at<P: AsRef<path::Path>>(&self, path: P) -> io::Result<Filesystem> {
        let mut sfs: statfs = unsafe { mem::zeroed() };
        if unsafe { statfs(path.as_ref().to_string_lossy().as_ptr(), &mut sfs) } != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "statfs() failed"))
        }
        Ok(sfs.to_fs())
    }

    fn block_device_statistics(&self) -> io::Result<BTreeMap<String, BlockDeviceStats>> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn networks(&self) -> io::Result<BTreeMap<String, Network>> {
        unix::networks()
    }

    fn network_stats(&self, interface: &str) -> io::Result<NetworkStats> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn cpu_temp(&self) -> io::Result<f32> {
        let mut temp: i32 = 0; sysctl!(CPU0TEMP, &mut temp, mem::size_of::<i32>());
        // The sysctl interface supports more units, but both amdtemp and coretemp always
        // use IK (deciKelvin)
        Ok((temp as f32 - 2731.5) / 10.0)
    }

    fn socket_stats(&self) -> io::Result<SocketStats> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }
}

fn measure_cpu() -> io::Result<Vec<CpuTime>> {
    let cpus = *CP_TIMES_SIZE / mem::size_of::<bsd::sysctl_cpu>();
    let mut data: Vec<bsd::sysctl_cpu> = Vec::with_capacity(cpus);
    unsafe { data.set_len(cpus) };

    sysctl!(KERN_CP_TIMES, &mut data[0], *CP_TIMES_SIZE);
    Ok(data.into_iter().map(|cpu| cpu.into()).collect())
}

fn zfs_arc_size() -> io::Result<usize> {
    let mut zfs_arc: usize = 0;
    sysctl!(ZFS_ARC_SIZE, &mut zfs_arc, mem::size_of::<usize>());
    Ok(zfs_arc)
}

#[repr(C)]
struct fsid_t {
    val: [i32; 2],
}

// FreeBSD's native struct. If you want to know what FreeBSD
// thinks about the POSIX statvfs struct, read man 3 statvfs :D
#[repr(C)]
struct statfs {
    f_version: u32,
    f_type: u32,
    f_flags: u64,
    f_bsize: u64,
    f_iosize: u64,
    f_blocks: u64,
    f_bfree: u64,
    f_bavail: i64,
    f_files: u64,
    f_ffree: i64,
    f_syncwrites: u64,
    f_asyncwrites: u64,
    f_syncreads: u64,
    f_asyncreads: u64,
    f_spare: [u64; 10],
    f_namemax: u32,
    f_owner: uid_t,
    f_fsid: fsid_t,
    f_charspare: [c_schar; 80],
    f_fstypename: [c_schar; 16],
    f_mntfromname: [c_schar; 88],
    f_mntonname: [c_schar; 88],
}

impl statfs {
    fn to_fs(&self) -> Filesystem {
        Filesystem {
            files: self.f_files as usize - self.f_ffree as usize,
            files_total: self.f_files as usize,
            files_avail: self.f_ffree as usize,
            free: ByteSize::b(self.f_bfree as usize * self.f_bsize as usize),
            avail: ByteSize::b(self.f_bavail as usize * self.f_bsize as usize),
            total: ByteSize::b(self.f_blocks as usize * self.f_bsize as usize),
            name_max: self.f_namemax as usize,
            fs_type: unsafe { ffi::CStr::from_ptr(&self.f_fstypename[0]).to_string_lossy().into_owned() },
            fs_mounted_from: unsafe { ffi::CStr::from_ptr(&self.f_mntfromname[0]).to_string_lossy().into_owned() },
            fs_mounted_on: unsafe { ffi::CStr::from_ptr(&self.f_mntonname[0]).to_string_lossy().into_owned() },
        }
    }
}

#[link(name = "c")]
extern "C" {
    #[link_name = "getmntinfo@FBSD_1.0"]
    fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int;
    #[link_name = "statfs@FBSD_1.0"]
    fn statfs(path: *const c_uchar, buf: *mut statfs) -> c_int;
}
<commit_msg>Use OsStr<commit_after>// You are likely to be eaten by a grue.

use std::{io, path, ptr, mem, ffi, slice, time};
use std::os::unix::ffi::OsStrExt;
use libc::{c_void, c_int, c_schar, c_uchar, size_t, uid_t, sysctl, sysctlnametomib, timeval};
use data::*;
use super::common::*;
use super::unix;
use super::bsd;

pub struct PlatformImpl;

macro_rules! sysctl_mib {
    ($len:expr, $name:expr) => {
        {
            let mut mib: [c_int; $len] = [0; $len];
            let mut sz: size_t = mib.len();
            let s = ffi::CString::new($name).unwrap();
            unsafe { sysctlnametomib(s.as_ptr(), &mut mib[0], &mut sz) };
            mib
        }
    }
}

macro_rules! sysctl {
    ($mib:expr, $dataptr:expr, $size:expr, $shouldcheck:expr) => {
        {
            let mib = &$mib;
            let mut size = $size;
            if unsafe { sysctl(&mib[0], mib.len() as u32,
                               $dataptr as *mut _ as *mut c_void, &mut size, ptr::null(), 0) } != 0 && $shouldcheck {
                return Err(io::Error::new(io::ErrorKind::Other, "sysctl() failed"))
            }
            size
        }
    };
    ($mib:expr, $dataptr:expr, $size:expr) => {
        sysctl!($mib, $dataptr, $size, true)
    }
}

lazy_static! {
    static ref KERN_CP_TIMES: [c_int; 2] = sysctl_mib!(2, "kern.cp_times");
    static ref KERN_BOOTTIME: [c_int; 2] = sysctl_mib!(2, "kern.boottime");
    static ref V_ACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_active_count");
    static ref V_INACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_inactive_count");
    static ref V_WIRE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_wire_count");
    static ref V_CACHE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_cache_count");
    static ref V_FREE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_free_count");
    static ref ZFS_ARC_SIZE: [c_int; 5] = sysctl_mib!(5, "kstat.zfs.misc.arcstats.size");
    static ref BATTERY_LIFE: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.life");
    static ref BATTERY_TIME: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.time");
    static ref ACLINE: [c_int; 3] = sysctl_mib!(3, "hw.acpi.acline");
    static ref CPU0TEMP: [c_int; 4] = sysctl_mib!(4, "dev.cpu.0.temperature");

    static ref CP_TIMES_SIZE: usize = {
        let mut size: usize = 0;
        unsafe { sysctl(&KERN_CP_TIMES[0], KERN_CP_TIMES.len() as u32,
                        ptr::null_mut(), &mut size, ptr::null(), 0) };
        size
    };
}

/// An implementation of `Platform` for FreeBSD.
/// See `Platform` for documentation.
impl Platform for PlatformImpl {
    #[inline(always)]
    fn new() -> Self {
        PlatformImpl
    }

    fn cpu_load(&self) -> io::Result<DelayedMeasurement<Vec<CPULoad>>> {
        let loads = try!(measure_cpu());
        Ok(DelayedMeasurement::new(
                Box::new(move || Ok(loads.iter()
                               .zip(try!(measure_cpu()).iter())
                               .map(|(prev, now)| (*now - prev).to_cpuload())
                               .collect::<Vec<_>>()))))
    }

    fn load_average(&self) -> io::Result<LoadAverage> {
        unix::load_average()
    }

    fn memory(&self) -> io::Result<Memory> {
        let mut active: usize = 0; sysctl!(V_ACTIVE_COUNT, &mut active, mem::size_of::<usize>());
        let mut inactive: usize = 0; sysctl!(V_INACTIVE_COUNT, &mut inactive, mem::size_of::<usize>());
        let mut wired: usize = 0; sysctl!(V_WIRE_COUNT, &mut wired, mem::size_of::<usize>());
        let mut cache: usize = 0; sysctl!(V_CACHE_COUNT, &mut cache, mem::size_of::<usize>(), false);
        let mut free: usize = 0; sysctl!(V_FREE_COUNT, &mut free, mem::size_of::<usize>());
        let arc = ByteSize::b(zfs_arc_size().unwrap_or(0));
        let pmem = PlatformMemory {
            active: ByteSize::kib(active << *bsd::PAGESHIFT),
            inactive: ByteSize::kib(inactive << *bsd::PAGESHIFT),
            wired: ByteSize::kib(wired << *bsd::PAGESHIFT) - arc,
            cache: ByteSize::kib(cache << *bsd::PAGESHIFT),
            zfs_arc: arc,
            free: ByteSize::kib(free << *bsd::PAGESHIFT),
        };
        Ok(Memory {
            total: pmem.active + pmem.inactive + pmem.wired + pmem.cache + arc + pmem.free,
            free: pmem.inactive + pmem.cache + arc + pmem.free,
            platform_memory: pmem,
        })
    }

    fn boot_time(&self) -> io::Result<DateTime<Utc>> {
        let mut data: timeval = unsafe { mem::zeroed() };
        sysctl!(KERN_BOOTTIME, &mut data, mem::size_of::<timeval>());
        Ok(DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(data.tv_sec.into(), data.tv_usec as u32), Utc))
    }

    fn battery_life(&self) -> io::Result<BatteryLife> {
        let mut life: usize = 0; sysctl!(BATTERY_LIFE, &mut life, mem::size_of::<usize>());
        let mut time: i32 = 0; sysctl!(BATTERY_TIME, &mut time, mem::size_of::<i32>());
        Ok(BatteryLife {
            remaining_capacity: life as f32 / 100.0,
            remaining_time: time::Duration::from_secs(if time < 0 { 0 } else { time as u64 }),
        })
    }

    fn on_ac_power(&self) -> io::Result<bool> {
        let mut on: usize = 0; sysctl!(ACLINE, &mut on, mem::size_of::<usize>());
        Ok(on == 1)
    }

    fn mounts(&self) -> io::Result<Vec<Filesystem>> {
        let mut mptr: *mut statfs = ptr::null_mut();
        let len = unsafe { getmntinfo(&mut mptr, 1 as i32) };
        if len < 1 {
            return Err(io::Error::new(io::ErrorKind::Other, "getmntinfo() failed"))
        }
        let mounts = unsafe { slice::from_raw_parts(mptr, len as usize) };
        Ok(mounts.iter().map(|m| m.to_fs()).collect::<Vec<_>>())
    }

    fn mount_at<P: AsRef<path::Path>>(&self, path: P) -> io::Result<Filesystem> {
        let mut sfs: statfs = unsafe { mem::zeroed() };
        if unsafe { statfs(path.as_ref().as_os_str().as_bytes().clone().as_ptr(), &mut sfs) } != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "statfs() failed"))
        }
        Ok(sfs.to_fs())
    }

    fn block_device_statistics(&self) -> io::Result<BTreeMap<String, BlockDeviceStats>> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn networks(&self) -> io::Result<BTreeMap<String, Network>> {
        unix::networks()
    }

    fn network_stats(&self, interface: &str) -> io::Result<NetworkStats> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }

    fn cpu_temp(&self) -> io::Result<f32> {
        let mut temp: i32 = 0; sysctl!(CPU0TEMP, &mut temp, mem::size_of::<i32>());
        // The sysctl interface supports more units, but both amdtemp and coretemp always
        // use IK (deciKelvin)
        Ok((temp as f32 - 2731.5) / 10.0)
    }

    fn socket_stats(&self) -> io::Result<SocketStats> {
        Err(io::Error::new(io::ErrorKind::Other, "Not supported"))
    }
}

fn measure_cpu() -> io::Result<Vec<CpuTime>> {
    let cpus = *CP_TIMES_SIZE / mem::size_of::<bsd::sysctl_cpu>();
    let mut data: Vec<bsd::sysctl_cpu> = Vec::with_capacity(cpus);
    unsafe { data.set_len(cpus) };

    sysctl!(KERN_CP_TIMES, &mut data[0], *CP_TIMES_SIZE);
    Ok(data.into_iter().map(|cpu| cpu.into()).collect())
}

fn zfs_arc_size() -> io::Result<usize> {
    let mut zfs_arc: usize = 0;
    sysctl!(ZFS_ARC_SIZE, &mut zfs_arc, mem::size_of::<usize>());
    Ok(zfs_arc)
}

#[repr(C)]
struct fsid_t {
    val: [i32; 2],
}

// FreeBSD's native struct. If you want to know what FreeBSD
// thinks about the POSIX statvfs struct, read man 3 statvfs :D
#[repr(C)]
struct statfs {
    f_version: u32,
    f_type: u32,
    f_flags: u64,
    f_bsize: u64,
    f_iosize: u64,
    f_blocks: u64,
    f_bfree: u64,
    f_bavail: i64,
    f_files: u64,
    f_ffree: i64,
    f_syncwrites: u64,
    f_asyncwrites: u64,
    f_syncreads: u64,
    f_asyncreads: u64,
    f_spare: [u64; 10],
    f_namemax: u32,
    f_owner: uid_t,
    f_fsid: fsid_t,
    f_charspare: [c_schar; 80],
    f_fstypename: [c_schar; 16],
    f_mntfromname: [c_schar; 88],
    f_mntonname: [c_schar; 88],
}

impl statfs {
    fn to_fs(&self) -> Filesystem {
        Filesystem {
            files: self.f_files as usize - self.f_ffree as usize,
            files_total: self.f_files as usize,
            files_avail: self.f_ffree as usize,
            free: ByteSize::b(self.f_bfree as usize * self.f_bsize as usize),
            avail: ByteSize::b(self.f_bavail as usize * self.f_bsize as usize),
            total: ByteSize::b(self.f_blocks as usize * self.f_bsize as usize),
            name_max: self.f_namemax as usize,
            fs_type: unsafe { ffi::CStr::from_ptr(&self.f_fstypename[0]).to_string_lossy().into_owned() },
            fs_mounted_from: unsafe { ffi::CStr::from_ptr(&self.f_mntfromname[0]).to_string_lossy().into_owned() },
            fs_mounted_on: unsafe { ffi::CStr::from_ptr(&self.f_mntonname[0]).to_string_lossy().into_owned() },
        }
    }
}

#[link(name = "c")]
extern "C" {
    #[link_name = "getmntinfo@FBSD_1.0"]
    fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int;
    #[link_name = "statfs@FBSD_1.0"]
    fn statfs(path: *const c_uchar, buf: *mut statfs) -> c_int;
}
<|endoftext|>


<commit_before>/*!
Attribute parsing

The attribute parser provides methods for pulling documentation out of
an AST's attributes.
*/

use syntax::ast;
use syntax::attr;
use core::tuple;

export CrateAttrs;
export parse_crate, parse_desc;
export parse_hidden;

type CrateAttrs = {
    name: Option<~str>
};

#[cfg(test)]
mod test {
    #[legacy_exports];

    fn parse_attributes(source: ~str) -> ~[ast::attribute] {
        use syntax::parse;
        use parse::parser;
        use parse::attr::parser_attr;
        use syntax::codemap;
        use syntax::diagnostic;

        let parse_sess = syntax::parse::new_parse_sess(None);
        let parser = parse::new_parser_from_source_str(
            parse_sess, ~[], ~"-", codemap::fss_none, @source);

        parser.parse_outer_attributes()
    }
}

fn doc_meta(
    attrs: ~[ast::attribute]
) -> Option<@ast::meta_item> {

    /*!
     * Given a vec of attributes, extract the meta_items contained in the \
     * doc attribute
     */

    let doc_metas = doc_metas(attrs);
    if vec::is_not_empty(doc_metas) {
        if vec::len(doc_metas) != 1u {
            warn!("ignoring %u doc attributes", vec::len(doc_metas) - 1u);
        }
        Some(doc_metas[0])
    } else {
        None
    }

}

fn doc_metas(
    attrs: ~[ast::attribute]
) -> ~[@ast::meta_item] {

    let doc_attrs = attr::find_attrs_by_name(attrs, ~"doc");
    let doc_metas = do doc_attrs.map |attr| {
        attr::attr_meta(attr::desugar_doc_attr(attr))
    };

    return doc_metas;
}

fn parse_crate(attrs: ~[ast::attribute]) -> CrateAttrs {
    let link_metas = attr::find_linkage_metas(attrs);

    {
        name: attr::last_meta_item_value_str_by_name(link_metas, ~"name")
    }
}

#[test]
fn should_extract_crate_name_from_link_attribute() {
    let source = ~"#[link(name = \"snuggles\")]";
    let attrs = test::parse_attributes(source);
    let attrs = parse_crate(attrs);
    assert attrs.name == Some(~"snuggles");
}

#[test]
fn should_not_extract_crate_name_if_no_link_attribute() {
    let source = ~"";
    let attrs = test::parse_attributes(source);
    let attrs = parse_crate(attrs);
    assert attrs.name == None;
}

#[test]
fn should_not_extract_crate_name_if_no_name_value_in_link_attribute() {
    let source = ~"#[link(whatever)]";
    let attrs = test::parse_attributes(source);
    let attrs = parse_crate(attrs);
    assert attrs.name == None;
}

fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> {
    match doc_meta(attrs) {
      Some(meta) => {
        attr::get_meta_item_value_str(meta)
      }
      None => None
    }
}

#[test]
fn parse_desc_should_handle_undocumented_mods() {
    let source = ~"";
    let attrs = test::parse_attributes(source);
    let attrs = parse_desc(attrs);
    assert attrs == None;
}

#[test]
fn parse_desc_should_parse_simple_doc_attributes() {
    let source = ~"#[doc = \"basic\"]";
    let attrs = test::parse_attributes(source);
    let attrs = parse_desc(attrs);
    assert attrs == Some(~"basic");
}

fn parse_hidden(attrs: ~[ast::attribute]) -> bool {
    do doc_metas(attrs).find |meta| {
        match attr::get_meta_item_list(meta) {
          Some(metas) => {
            let hiddens = attr::find_meta_items_by_name(metas, ~"hidden");
            vec::is_not_empty(hiddens)
          }
          None => false
        }
    }.is_some()
}

#[test]
fn should_parse_hidden_attribute() {
    let source = ~"#[doc(hidden)]";
    let attrs = test::parse_attributes(source);
    assert parse_hidden(attrs) == true;
}

#[test]
fn should_parse_hidden_attribute_with_other_docs() {
    let source = ~"#[doc = \"foo\"] #[doc(hidden)] #[doc = \"foo\"]";
    let attrs = test::parse_attributes(source);
    assert parse_hidden(attrs) == true;
}

#[test]
fn should_not_parse_non_hidden_attribute() {
    let source = ~"#[doc = \"\"]";
    let attrs = test::parse_attributes(source);
    assert parse_hidden(attrs) == false;
}
<commit_msg>Fix and test for issue #3780.<commit_after>/*!
Attribute parsing

The attribute parser provides methods for pulling documentation out of
an AST's attributes.
*/

use syntax::ast;
use syntax::attr;
use core::tuple;

export CrateAttrs;
export parse_crate, parse_desc;
export parse_hidden;

type CrateAttrs = {
    name: Option<~str>
};

#[cfg(test)]
mod test {
    #[legacy_exports];

    fn parse_attributes(source: ~str) -> ~[ast::attribute] {
        use syntax::parse;
        use parse::parser;
        use parse::attr::parser_attr;
        use syntax::codemap;
        use syntax::diagnostic;

        let parse_sess = syntax::parse::new_parse_sess(None);
        let parser = parse::new_parser_from_source_str(
            parse_sess, ~[], ~"-", codemap::fss_none, @source);

        parser.parse_outer_attributes()
    }
}

fn doc_metas(
    attrs: ~[ast::attribute]
) -> ~[@ast::meta_item] {

    let doc_attrs = attr::find_attrs_by_name(attrs, ~"doc");
    let doc_metas = do doc_attrs.map |attr| {
        attr::attr_meta(attr::desugar_doc_attr(attr))
    };

    return doc_metas;
}

fn parse_crate(attrs: ~[ast::attribute]) -> CrateAttrs {
    let link_metas = attr::find_linkage_metas(attrs);

    {
        name: attr::last_meta_item_value_str_by_name(link_metas, ~"name")
    }
}

#[test]
fn should_extract_crate_name_from_link_attribute() {
    let source = ~"#[link(name = \"snuggles\")]";
    let attrs = test::parse_attributes(source);
    let attrs = parse_crate(attrs);
    assert attrs.name == Some(~"snuggles");
}

#[test]
fn should_not_extract_crate_name_if_no_link_attribute() {
    let source = ~"";
    let attrs = test::parse_attributes(source);
    let attrs = parse_crate(attrs);
    assert attrs.name == None;
}

#[test]
fn should_not_extract_crate_name_if_no_name_value_in_link_attribute() {
    let source = ~"#[link(whatever)]";
    let attrs = test::parse_attributes(source);
    let attrs = parse_crate(attrs);
    assert attrs.name == None;
}

fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> {
    let doc_strs = do doc_metas(attrs).filter_map |meta| {
        attr::get_meta_item_value_str(*meta)
    };
    if doc_strs.is_empty() {
        None
    } else {
        Some(str::connect(doc_strs, "\n"))
    }
}

#[test]
fn parse_desc_should_handle_undocumented_mods() {
    let source = ~"";
    let attrs = test::parse_attributes(source);
    let attrs = parse_desc(attrs);
    assert attrs == None;
}

#[test]
fn parse_desc_should_parse_simple_doc_attributes() {
    let source = ~"#[doc = \"basic\"]";
    let attrs = test::parse_attributes(source);
    let attrs = parse_desc(attrs);
    assert attrs == Some(~"basic");
}

fn parse_hidden(attrs: ~[ast::attribute]) -> bool {
    do doc_metas(attrs).find |meta| {
        match attr::get_meta_item_list(meta) {
          Some(metas) => {
            let hiddens = attr::find_meta_items_by_name(metas, ~"hidden");
            vec::is_not_empty(hiddens)
          }
          None => false
        }
    }.is_some()
}

#[test]
fn should_parse_hidden_attribute() {
    let source = ~"#[doc(hidden)]";
    let attrs = test::parse_attributes(source);
    assert parse_hidden(attrs) == true;
}

#[test]
fn should_parse_hidden_attribute_with_other_docs() {
    let source = ~"#[doc = \"foo\"] #[doc(hidden)] #[doc = \"foo\"]";
    let attrs = test::parse_attributes(source);
    assert parse_hidden(attrs) == true;
}

#[test]
fn should_not_parse_non_hidden_attribute() {
    let source = ~"#[doc = \"\"]";
    let attrs = test::parse_attributes(source);
    assert parse_hidden(attrs) == false;
}

#[test]
fn should_concatenate_multiple_doc_comments() {
    let source = ~"/// foo\n/// bar";
    let desc = parse_desc(test::parse_attributes(source));
    assert desc == Some(~"foo\nbar");
}

<|endoftext|>


<commit_before>//! Proxy engine
//!
//! This module is intended for processing incoming requests from clients,
//! handling occurred errors during a work, communicating with a message
//! broker and preparing appropriate responses in the certain format.
//!

pub mod rabbitmq;
pub mod router;
pub mod serializer;

use std::cell::{RefCell};
use std::rc::{Rc};
use std::str::{from_utf8};
use std::vec::Vec;

pub use self::router::{Router, Endpoint, extract_endpoints};
pub use self::serializer::{Serializer, JsonMessage};
pub use self::rabbitmq::{RabbitMQClient, RabbitMQFuture};

use super::cli::{CliOptions};
use super::error::{Result, PathfinderError};

use json::{parse as json_parse};
use futures::{Stream};
use futures::future::{Future};
use futures::sync::{mpsc};
use lapin_futures_rustls::lapin::types::{AMQPValue, FieldTable};
use lapin_futures_rustls::lapin::channel::{ConfirmSelectOptions};
use lapin_futures_rustls::lapin::channel::{BasicPublishOptions, BasicProperties, BasicConsumeOptions};
use lapin_futures_rustls::lapin::channel::{QueueDeclareOptions, QueueDeleteOptions, QueueBindOptions};
use tokio_core::reactor::{Handle};
use tungstenite::{Message};
use uuid::{Uuid};

/// Proxy engine for processing messages, handling errors and communicating with a message broker.
pub struct Engine {
    router: Rc<Box<Router>>,
    rabbitmq_client: Rc<RefCell<Box<RabbitMQClient>>>
}

impl Engine {
    /// Returns a new instance of `Engine`.
    pub fn new(cli: &CliOptions, router: Box<Router>) -> Engine {
        Engine {
            router: Rc::new(router),
            rabbitmq_client: Rc::new(RefCell::new(Box::new(RabbitMQClient::new(cli))))
        }
    }

    /// Main handler for generating a response per each incoming request.
    pub fn handle(&self, message: JsonMessage, transmitter: mpsc::UnboundedSender<Message>, handle: &Handle) -> RabbitMQFuture {
        let message_nested = message.clone();
        let url = message_nested["url"].as_str().unwrap();

        let endpoint = self.router.clone().match_url_or_default(&url);
        let endpoint_link = endpoint.clone();
        let endpoint_publish = endpoint.clone();

        let queue_name = Rc::new(format!("{}", Uuid::new_v4()));
        let queue_name_bind = queue_name.clone();
        let queue_name_response = queue_name.clone();
        let queue_name_consumer = queue_name.clone();
        let queue_name_delete = queue_name.clone();

        let request_headers = self.prepare_request_headers(&message_nested, endpoint.clone());
        let client_future = self.rabbitmq_client.borrow().get_future(handle);

        Box::new(client_future
            // 1. Create a channel
            .and_then(move |client| {
                client.create_confirm_channel(ConfirmSelectOptions::default())
            })

            // 2. Declare a response queue
            .and_then(move |channel| {
                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(|_| channel)
            })

            // 3. Link the response queue the exchange
            .and_then(move |channel| {
                channel.queue_bind(
                    &queue_name_bind,
                    &endpoint_link.get_response_exchange(),
                    &endpoint_link.get_microservice(),
                    &QueueBindOptions::default(),
                    &FieldTable::new()
                )
                    .map(|_| channel)
            })

             // 4. Publish message into the microservice queue and make ensure that it's delivered
            .and_then(move |channel| {
                let publish_message_options = BasicPublishOptions {
                    mandatory: true,
                    immediate: false,
                    ..Default::default()
                };

                let mut message_headers = FieldTable::new();
                for &(ref key, ref value) in request_headers.clone().iter() {
                    let header_name = key.to_string();
                    let header_value = AMQPValue::LongString(value.to_string());
                    message_headers.insert(header_name, header_value);
                }

                let event_name = message["event-name"].as_str().unwrap_or("null");

                let basic_properties = BasicProperties {
                    content_type: Some("application/json".to_string()),
                    headers: Some(message_headers),                       // Headers for the message
                    delivery_mode: Some(2),                               // Message must be persistent
                    reply_to: Some(queue_name_response.to_string()),      // Response queue
                    correlation_id: Some(event_name.clone().to_string()), // Event name
                    ..Default::default()
                };

                channel.basic_publish(
                    &endpoint_publish.get_request_exchange(),
                    &endpoint_publish.get_microservice(),
                    message["content"].dump().as_bytes(),
                    &publish_message_options,
                    basic_properties
                )
                    .map(|_confirmation| channel)
            })

            // 5. Consume a response message from the queue, that was declared on the 2nd step
            .and_then(move |channel| {
                channel.basic_consume(
                    &queue_name_consumer,
                    "response_consumer",
                    &BasicConsumeOptions::default(),
                    &FieldTable::new()
                )
                    .and_then(move |stream| {
                        stream.take(1)
                              .into_future()
                              .map_err(|(err, _)| err)
                              .map(move |(message, _)| (channel, message.unwrap()))
                    })
            })

            // 6. Prepare a response for a client, serialize and sent via WebSocket transmitter
            .and_then(move |(channel, message)| {
                let raw_data = from_utf8(&message.data).unwrap();
                let json = Rc::new(Box::new(json_parse(raw_data).unwrap()));
                let serializer = Serializer::new();
                let response = serializer.serialize(json.dump()).unwrap();
                transmitter.unbounded_send(response).unwrap();
                channel.basic_ack(message.delivery_tag)
                    .map(move |_| channel)
            })

            // 7. Unbind the response queue from the exchange point
            // TODO: Uncomment this code when my PR for queue_unbind will be merged
            //.and_then(move |channel| {
            //    channel.queue_unbind(
            //        &queue_name_unbind,
            //        &response_exchange_name,
            //        &endpoint_unbind.get_microservice(),
            //        &QueueUnbindOptions::default(),
            //        &FieldTable::new()
            //    )
            //        .map(|_| channel)
            //})

            // 8. Delete the response queue
            .and_then(move |channel| {
                let queue_delete_options = QueueDeleteOptions {
                    if_unused: false,
                    if_empty: false,
                    ..Default::default()
                };

                channel.queue_delete(&queue_name_delete, &queue_delete_options)
                    .map(|_| channel)
            })

            // 9. Close the channel
            .and_then(move |channel| {
                channel.close(200, "Close the channel.")
            })

            .then(move |result| {
                match result {
                    Ok(_) => Ok(()),
                    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))
                    }
                }
            })
        )
    }

    /// Transforms an error (which is a string) into JSON object in the special format.
    pub fn wrap_an_error(&self, err: &str) -> Message {
        let json_error_message = object!("details" => err);
        let serializer = Serializer::new();
        serializer.serialize(json_error_message.dump()).unwrap()
    }

    /// Serialize a JSON object into message.
    pub fn serialize_message(&self, json: JsonMessage) -> Message {
        let serializer = Serializer::new();
        serializer.serialize(json.dump()).unwrap()
    }

    /// Deserialize a message into JSON object.
    pub fn deserialize_message(&self, message: &Message) -> Result<JsonMessage> {
        let serializer = Serializer::new();
        serializer.deserialize(message)
    }

    /// Prepares a list of key-value pairs for headers in message.
    fn prepare_request_headers(&self, json: &JsonMessage, endpoint: Rc<Box<Endpoint>>) -> Box<Vec<(String, String)>> {
        Box::new(vec![
            (String::from("Microservice-Name"), endpoint.get_microservice()),
            (String::from("Request-URI"), endpoint.get_url()),
            (String::from("Event-Name"), json["event-name"].as_str().unwrap_or("null").to_string()),
            (String::from("Token"), json["token"].as_str().unwrap_or("null").to_string())
        ])
    }
}
<commit_msg>Fixed issue with creating the response queue<commit_after>//! Proxy engine
//!
//! This module is intended for processing incoming requests from clients,
//! handling occurred errors during a work, communicating with a message
//! broker and preparing appropriate responses in the certain format.
//!

pub mod rabbitmq;
pub mod router;
pub mod serializer;

use std::cell::{RefCell};
use std::rc::{Rc};
use std::str::{from_utf8};
use std::vec::Vec;

pub use self::router::{Router, Endpoint, extract_endpoints};
pub use self::serializer::{Serializer, JsonMessage};
pub use self::rabbitmq::{RabbitMQClient, RabbitMQFuture};

use super::cli::{CliOptions};
use super::error::{Result, PathfinderError};

use json::{parse as json_parse};
use futures::{Stream};
use futures::future::{Future};
use futures::sync::{mpsc};
use lapin_futures_rustls::lapin::types::{AMQPValue, FieldTable};
use lapin_futures_rustls::lapin::channel::{ConfirmSelectOptions};
use lapin_futures_rustls::lapin::channel::{BasicPublishOptions, BasicProperties, BasicConsumeOptions};
use lapin_futures_rustls::lapin::channel::{QueueDeclareOptions, QueueDeleteOptions, QueueBindOptions};
use tokio_core::reactor::{Handle};
use tungstenite::{Message};
use uuid::{Uuid};

/// Proxy engine for processing messages, handling errors and communicating with a message broker.
pub struct Engine {
    router: Rc<Box<Router>>,
    rabbitmq_client: Rc<RefCell<Box<RabbitMQClient>>>
}

impl Engine {
    /// Returns a new instance of `Engine`.
    pub fn new(cli: &CliOptions, router: Box<Router>) -> Engine {
        Engine {
            router: Rc::new(router),
            rabbitmq_client: Rc::new(RefCell::new(Box::new(RabbitMQClient::new(cli))))
        }
    }

    /// Main handler for generating a response per each incoming request.
    pub fn handle(&self, message: JsonMessage, transmitter: mpsc::UnboundedSender<Message>, handle: &Handle) -> RabbitMQFuture {
        let message_nested = message.clone();
        let url = message_nested["url"].as_str().unwrap();

        let endpoint = self.router.clone().match_url_or_default(&url);
        let endpoint_link = endpoint.clone();
        let endpoint_publish = endpoint.clone();

        let queue_name = Rc::new(format!("{}", Uuid::new_v4()));
        let queue_name_bind = queue_name.clone();
        let queue_name_response = queue_name.clone();
        let queue_name_consumer = queue_name.clone();
        let queue_name_delete = queue_name.clone();

        let request_headers = self.prepare_request_headers(&message_nested, endpoint.clone());
        let client_future = self.rabbitmq_client.borrow().get_future(handle);

        Box::new(client_future
            // 1. Create a channel
            .and_then(move |client| {
                client.create_confirm_channel(ConfirmSelectOptions::default())
            })

            // 2. Declare a response queue
            .and_then(move |channel| {
                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(|_| channel)
            })

            // 3. Link the response queue the exchange
            .and_then(move |channel| {
                channel.queue_bind(
                    &queue_name_bind,
                    &endpoint_link.get_response_exchange(),
                    &queue_name_bind,
                    &QueueBindOptions::default(),
                    &FieldTable::new()
                )
                    .map(|_| channel)
            })

             // 4. Publish message into the microservice queue and make ensure that it's delivered
            .and_then(move |channel| {
                let publish_message_options = BasicPublishOptions {
                    mandatory: true,
                    immediate: false,
                    ..Default::default()
                };

                let mut message_headers = FieldTable::new();
                for &(ref key, ref value) in request_headers.clone().iter() {
                    let header_name = key.to_string();
                    let header_value = AMQPValue::LongString(value.to_string());
                    message_headers.insert(header_name, header_value);
                }

                let event_name = message["event-name"].as_str().unwrap_or("null");

                let basic_properties = BasicProperties {
                    content_type: Some("application/json".to_string()),
                    headers: Some(message_headers),                       // Headers for the message
                    delivery_mode: Some(2),                               // Message must be persistent
                    reply_to: Some(queue_name_response.to_string()),      // Response queue
                    correlation_id: Some(event_name.clone().to_string()), // Event name
                    ..Default::default()
                };

                channel.basic_publish(
                    &endpoint_publish.get_request_exchange(),
                    &endpoint_publish.get_microservice(),
                    message["content"].dump().as_bytes(),
                    &publish_message_options,
                    basic_properties
                )
                    .map(|_confirmation| channel)
            })

            // 5. Consume a response message from the queue, that was declared on the 2nd step
            .and_then(move |channel| {
                channel.basic_consume(
                    &queue_name_consumer,
                    "response_consumer",
                    &BasicConsumeOptions::default(),
                    &FieldTable::new()
                )
                    .and_then(move |stream| {
                        stream.take(1)
                              .into_future()
                              .map_err(|(err, _)| err)
                              .map(move |(message, _)| (channel, message.unwrap()))
                    })
            })

            // 6. Prepare a response for a client, serialize and sent via WebSocket transmitter
            .and_then(move |(channel, message)| {
                let raw_data = from_utf8(&message.data).unwrap();
                let json = Rc::new(Box::new(json_parse(raw_data).unwrap()));
                let serializer = Serializer::new();
                let response = serializer.serialize(json.dump()).unwrap();
                transmitter.unbounded_send(response).unwrap();
                channel.basic_ack(message.delivery_tag)
                    .map(move |_| channel)
            })

            // 7. Unbind the response queue from the exchange point
            // TODO: Uncomment this code when my PR for queue_unbind will be merged
            //.and_then(move |channel| {
            //    channel.queue_unbind(
            //        &queue_name_unbind,
            //        &response_exchange_name,
            //        &endpoint_unbind.get_microservice(),
            //        &QueueUnbindOptions::default(),
            //        &FieldTable::new()
            //    )
            //        .map(|_| channel)
            //})

            // 8. Delete the response queue
            .and_then(move |channel| {
                let queue_delete_options = QueueDeleteOptions {
                    if_unused: false,
                    if_empty: false,
                    ..Default::default()
                };

                channel.queue_delete(&queue_name_delete, &queue_delete_options)
                    .map(|_| channel)
            })

            // 9. Close the channel
            .and_then(move |channel| {
                channel.close(200, "Close the channel.")
            })

            .then(move |result| {
                match result {
                    Ok(_) => Ok(()),
                    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))
                    }
                }
            })
        )
    }

    /// Transforms an error (which is a string) into JSON object in the special format.
    pub fn wrap_an_error(&self, err: &str) -> Message {
        let json_error_message = object!("details" => err);
        let serializer = Serializer::new();
        serializer.serialize(json_error_message.dump()).unwrap()
    }

    /// Serialize a JSON object into message.
    pub fn serialize_message(&self, json: JsonMessage) -> Message {
        let serializer = Serializer::new();
        serializer.serialize(json.dump()).unwrap()
    }

    /// Deserialize a message into JSON object.
    pub fn deserialize_message(&self, message: &Message) -> Result<JsonMessage> {
        let serializer = Serializer::new();
        serializer.deserialize(message)
    }

    /// Prepares a list of key-value pairs for headers in message.
    fn prepare_request_headers(&self, json: &JsonMessage, endpoint: Rc<Box<Endpoint>>) -> Box<Vec<(String, String)>> {
        Box::new(vec![
            (String::from("Microservice-Name"), endpoint.get_microservice()),
            (String::from("Request-URI"), endpoint.get_url()),
            (String::from("Event-Name"), json["event-name"].as_str().unwrap_or("null").to_string()),
            (String::from("Token"), json["token"].as_str().unwrap_or("null").to_string())
        ])
    }
}
<|endoftext|>


<commit_before>pub fn decode_at_index(s: String, k: i32) -> String {
    use std::iter::FromIterator;
    let mut length = 0_usize;
    let mut cache = Vec::new();
    let mut result = String::new();
    let mut cache_clean = false;
    for c in s.chars() {
        if let Some(times) = c.to_digit(10) {
            length *= times as usize;
            //result += &String::from_iter(cache);
            //result = result.repeat(times as usize);
            cache_clean = true;
        } else {
            if cache_clean {
                cache = vec![];
                cache_clean = false;
            }
            length += 1;
            cache.push(c);
        }

        //println!("{}", result);
        if length == k as usize {
            return cache.pop().unwrap().to_string();
        }

        if length > k as usize {
            println!("{}", length);
            return result.get(k as usize - 1..k as usize).unwrap().into();
        }
    }

    result
}

fn inner_helper(s: &str, mut k: i32, last_cache: Vec<char>) -> String {
    let mut cache = last_cache;
    for (ind, c) in s.chars().enumerate() {
        if let Some(times) = c.to_digit(10) {
            if times as i32 * cache.len() as i32 >= k {
                return cache[(k % cache.len() as i32) as usize].into();
            } else {
                return inner_helper(
                    &s[ind..s.len()],
                    k - times as i32 * cache.len() as i32,
                    cache,
                );
            }
        } else {
            k -= 1;
            if k == 0 {
                return c.into();
            }
        }
    }
}

fn main() {
    dbg!(decode_at_index("leet2code3".to_string(), 10));
    dbg!(decode_at_index("ha22".to_string(), 5));
    dbg!(decode_at_index("a2345678999999999999999".to_string(), 1));
    dbg!(decode_at_index("a23".to_string(), 6));
}
<commit_msg>a hammer<commit_after>// pub fn decode_at_index(s: String, k: i32) -> String {
//     use std::iter::FromIterator;
//     let mut length = 0_usize;
//     let mut cache = Vec::new();
//     let mut result = String::new();
//     let mut cache_clean = false;
//     for c in s.chars() {
//         if let Some(times) = c.to_digit(10) {
//             length *= times as usize;
//             //result += &String::from_iter(cache);
//             //result = result.repeat(times as usize);
//             cache_clean = true;
//         } else {
//             if cache_clean {
//                 cache = vec![];
//                 cache_clean = false;
//             }
//             length += 1;
//             cache.push(c);
//         }

//         //println!("{}", result);
//         if length == k as usize {
//             return cache.pop().unwrap().to_string();
//         }

//         if length > k as usize {
//             println!("{}", length);
//             return result.get(k as usize - 1..k as usize).unwrap().into();
//         }
//     }

//     result
// }

pub fn decode_at_index(s: String, k: i32) -> String {
    inner_helper(&s, k, 0, vec![])
}

fn inner_helper(s: &str, k: i32, last_sum_k: i32, last_cache: Vec<char>) -> String {
    println!("s: {}, k: {}, last_cache: {:?}", s, k, last_cache);
    let mut cache = last_cache;
    let mut cache_new = false;
    let mut mut_k = k;
    for (ind, c) in s.chars().enumerate() {
        println!("cache is: {:?}", cache);
        if let Some(times) = c.to_digit(10) {
            dbg!(times as i32 * cache.len() as i32);
            if (times as i32 * cache.len() as i32) >= k {
                if k > cache.len() as i32 {
                    return cache[((k + 1) % cache.len() as i32) as usize].to_string();
                } else {
                    return cache[k as usize - 1].to_string();
                }
            } else {
                return inner_helper(
                    &s[ind + 1..s.len()],
                    k - times as i32 * (cache.len() as i32 + last_sum_k),
                    times as i32 * (cache.len() as i32 + last_sum_k),
                    cache,
                );
            }
        } else {
            mut_k -= 1;
            if mut_k == 0 {
                return c.to_string();
            }

            if !cache_new {
                cache = vec![];
                cache_new = true;
            }
            cache.push(c);
        }
    }

    if k > cache.len() as i32 {
        return cache[((k + 1) % cache.len() as i32) as usize].to_string();
    } else {
        return cache[k as usize - 1].to_string();
    }
}

fn main() {
    // assert_eq!(
    //     decode_at_index("leet2code3".to_string(), 10),
    //     "o".to_string()
    // );
    // assert_eq!(decode_at_index("ha22".to_string(), 5), "h".to_string());
    // assert_eq!(
    //     decode_at_index("a2345678999999999999999".to_string(), 1),
    //     "a".to_string()
    // );
    // assert_eq!(decode_at_index("a23".to_string(), 6), "a".to_string());

    assert_eq!(
        decode_at_index("a2b3c4d5e6f7g8h9".to_string(), 9),
        "c".to_string()
    );
}
<|endoftext|>