<commit_before>mod log;
use capnp;
use rand;
use raft_capnp::{append_entries, append_entries_reply,
                 request_vote, request_vote_reply};
use rpc::{RpcError};
use rpc::server::{RpcObject, RpcServer};
use std::net::{SocketAddr};
use std::time::{Duration, Instant};
use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};

use self::log::{Log, MemoryLog, Entry};
use std::time;
use std::io::Error as IoError;
use rand::distributions::{IndependentSample, Range};

// Constants
// TODO: Many of these should be overwritable by Config
const ELECTION_TIMEOUT_MIN: u64 = 150; // min election timeout wait value in m.s.
const ELECTION_TIMEOUT_MAX: u64 = 300; // min election timeout wait value in m.s.
const HEARBEAT_INTERVAL: u64    = 75; // time between hearbeats

pub struct Config {
    cluster: Vec<SocketAddr>,
    leader: SocketAddr,
    addr: SocketAddr,
    heartbeat_timeout: Duration,
}

impl Config {
    pub fn new (cluster: Vec<SocketAddr>, leader: SocketAddr,
                addr: SocketAddr, heartbeat_timeout: Duration) -> Config {
        Config {
            cluster: cluster,
            leader: leader,
            addr: addr,
            heartbeat_timeout: heartbeat_timeout,
        }
    }

    // TODO eventually implement
    // pub fn fromFile (file: String) -> Config {
    //
    // }
}

// States that each machine can be in!
pub enum State {
    CANDIDATE,
    LEADER,
    FOLLOWER,
}

enum RpcType {
    APPEND_ENTRIES,
    REQUEST_VOTE,
}

struct AppendEntriesMessage {
    term: u64,
    leader_id: u64,
    prev_log_index: u64,
    prev_log_term: u64,
    entries: Entry,
    leader_commit: u64,
}

struct AppendEntriesReply {
    term: u64,
    success: u64,
}

struct RequestVoteMessage {
    term: u64,
    candidate_id: u64,
    last_log_index: u64,
    las_log_term: u64,
}

struct RequestVoteReply {
    term: u64,
    vote_granted: u64,
}

enum PeerThreadMessage {
    AppendEntries (AppendEntriesMessage),
    RequestVote (RequestVoteMessage),
}

enum PeerThreadResponse {
    AppendEntries (AppendEntriesReply),
    RequestVote (RequestVoteReply),
}

pub struct PeerHandle {
    to_peer: Sender<PeerThreadMessage>,
    from_peer: Receiver<PeerThreadMessage>,
}

pub struct Peer {
    addr: SocketAddr,
    commit_index: u64,
    pending_entries: Vec<Entry>,
    to_main: Sender<PeerThreadMessage>,
    from_main: Receiver<PeerThreadMessage>,
}

impl Peer {
    pub fn start (addr: SocketAddr) -> PeerHandle {
        let (to_peer, from_main) = channel();
        let (to_main, from_peer) = channel();
        let commit_index = 0;

        thread::spawn(move || {
            let peer = Peer {
                addr: addr,
                commit_index: commit_index,
                pending_entries: vec![],
                to_main: to_main,
                from_main: from_main,
            };
            peer.main();
        });

        PeerHandle {
            to_peer: to_peer,
            from_peer: from_peer,
        }
    }

    pub fn send_append_entries (&mut self, entry: AppendEntriesMessage) {
        unimplemented!()
        // TODO (syd)
        // 1. Construct an empty append_entries rpc
        // 2. Copy in entries from |ro_log| if peer commit index is behind.
    }

    pub fn send_request_vote (&self, vote: RequestVoteMessage) {
        unimplemented!()
    }

    // Main loop for this machine to push to Peers.
    fn main (mut self) {
        loop {
            match self.from_main.recv().unwrap() { // If recv fails, we in deep shit already, so just unwrap
                PeerThreadMessage::AppendEntries(entry) => self.send_append_entries(entry),
                PeerThreadMessage::RequestVote(vote) => self.send_request_vote(vote)
            }
        }
    }
}

pub struct Server {
    state: State,
    current_term: u64,
    log: Arc<Mutex<Log>>,
    peers: Vec<PeerHandle>,
    addr: SocketAddr,
    last_leader_contact: Instant,
    voted_for: Option<SocketAddr>
}

///
/// Starts up a new raft server with the given config.
/// This is mostly just a bootstrapper for now. It probably won't end up in the public API
/// As of right now this function does not return. It just runs the state machine as long as it's
/// in a live thread.
///
pub fn start_server(config: Config) -> ! {
    let server = Server::new(config).unwrap();

    // The server starts up in a follower state. Set a timeout to become a candidate.

    loop {
        match server.state {
            State::FOLLOWER => {
                let btwn = Range::new(ELECTION_TIMEOUT_MIN, ELECTION_TIMEOUT_MAX);
                let mut range = rand::thread_rng();
                let sleep_time = btwn.ind_sample(&mut range);
                thread::sleep(time::Duration::from_millis(sleep_time));

                // if last_leader_contact < election timeout, start an election
            },
            State::CANDIDATE => {
                // same as above?
                unimplemented!()
            },
            State::LEADER => {
                // sleep and then send a hearbeat?
                unimplemented!()
            }
        }
    }
}

impl Server {
    pub fn new (config: Config) -> Result<Server, IoError> {
        let addr = config.addr;
        // 1. Start RPC request handlers
        let append_entries_handler: Box<RpcObject> = Box::new(AppendEntriesHandler {});
        let services = vec![
            (1, append_entries_handler),
        ];
        let mut server = RpcServer::new_with_services(services);
        try!(
            server.bind((config.addr.ip(), config.addr.port()))
            .and_then(|_| {
                server.repl()
            })
        );

        // 2. Start peer threads.
        let peers = config.cluster.into_iter()
            .filter(move |x| *x != addr) // filter all computers that aren't me
            .map(|x| Peer::start(x))
            .collect::<Vec<PeerHandle>>();

        let log = Arc::new(Mutex::new(MemoryLog::new()));

        // 3. Construct server state object.
        Ok(Server {
            state: State::FOLLOWER,
            current_term: 0,
            log: log,
            peers: peers,
            addr: addr,
            voted_for: None,
            last_leader_contact: Instant::now()
        })
    }

    fn start_election(&mut self) {
        self.state = State::CANDIDATE;

        // tell each peer to send out RequestToVote RPCs
    }
}

struct AppendEntriesHandler {}

impl RpcObject for AppendEntriesHandler {
    fn handle_rpc (&self, params: capnp::any_pointer::Reader, result: capnp::any_pointer::Builder)
        -> Result<(), RpcError>
    {
        // TODO (syd) implement
        // 1. Ensure prevLogIndex matches our own.
        // 2. Append outstanding log entries.
        // 3. Construct reply.
        params.get_as::<append_entries::Reader>()
           .map(|append_entries| {
               result.init_as::<append_entries_reply::Builder>().set_success(true);
           })
           .map_err(RpcError::Capnp)
    }
}
<commit_msg>WIP: leader election<commit_after>mod log;
use capnp;
use rand;
use raft_capnp::{append_entries, append_entries_reply,
                 request_vote, request_vote_reply};
use rpc::{RpcError};
use rpc::server::{RpcObject, RpcServer};
use std::net::{SocketAddr};
use std::time::{Duration, Instant};
use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver};

use self::log::{Log, MemoryLog, Entry};
use std::time;
use std::io::Error as IoError;
use rand::distributions::{IndependentSample, Range};

// Constants
// TODO: Many of these should be overwritable by Config
const ELECTION_TIMEOUT_MIN: u64 = 150; // min election timeout wait value in m.s.
const ELECTION_TIMEOUT_MAX: u64 = 300; // min election timeout wait value in m.s.
const HEARBEAT_INTERVAL: u64    = 75; // time between hearbeats

pub struct Config {
    cluster: Vec<SocketAddr>,
    leader: SocketAddr,
    addr: SocketAddr,
    heartbeat_timeout: Duration,
}

impl Config {
    pub fn new (cluster: Vec<SocketAddr>, leader: SocketAddr,
                addr: SocketAddr, heartbeat_timeout: Duration) -> Config {
        Config {
            cluster: cluster,
            leader: leader,
            addr: addr,
            heartbeat_timeout: heartbeat_timeout,
        }
    }

    // TODO eventually implement
    // pub fn fromFile (file: String) -> Config {
    //
    // }
}

// States that each machine can be in!
pub enum State {
    CANDIDATE,
    LEADER,
    FOLLOWER,
}

enum RpcType {
    APPEND_ENTRIES,
    REQUEST_VOTE,
}

struct AppendEntriesMessage {
    term: u64,
    leader_id: u64,
    prev_log_index: u64,
    prev_log_term: u64,
    entries: Entry,
    leader_commit: u64,
}

struct AppendEntriesReply {
    term: u64,
    success: u64,
}

struct RequestVoteMessage {
    term: u64,
    candidate_id: u64,
    last_log_index: u64,
    las_log_term: u64,
}

struct RequestVoteReply {
    term: u64,
    vote_granted: u64,
}

enum PeerThreadMessage {
    AppendEntries (AppendEntriesMessage),
    RequestVote (RequestVoteMessage),
}

enum PeerThreadResponse {
    AppendEntries (AppendEntriesReply),
    RequestVote (RequestVoteReply),
}

pub struct PeerHandle {
    to_peer: Sender<PeerThreadMessage>,
    //from_peer: Receiver<PeerThreadMessage>,
}

pub struct Peer {
    addr: SocketAddr,
    commit_index: u64,
    pending_entries: Vec<Entry>,
    to_main: Sender<PeerThreadMessage>,
    from_main: Receiver<PeerThreadMessage>,
}

impl Peer {
    fn start (addr: SocketAddr, to_main: Sender<PeerThreadMessage>) -> PeerHandle {
        let (to_peer, from_main) = channel();
        //let (to_main, from_peer) = channel();
        let commit_index = 0;

        thread::spawn(move || {
            let peer = Peer {
                addr: addr,
                commit_index: commit_index,
                pending_entries: vec![],
                to_main: to_main,
                from_main: from_main,
            };
            peer.main();
        });

        PeerHandle {
            to_peer: to_peer,
            //from_peer: from_peer,
        }
    }

    pub fn send_append_entries (&mut self, entry: AppendEntriesMessage) {
        unimplemented!()
        // TODO (syd)
        // 1. Construct an empty append_entries rpc
        // 2. Copy in entries from |ro_log| if peer commit index is behind.
    }

    pub fn send_request_vote (&self, vote: RequestVoteMessage) {
        unimplemented!()
    }

    // Main loop for this machine to push to Peers.
    fn main (mut self) {
        loop {
            match self.from_main.recv().unwrap() { // If recv fails, we in deep shit already, so just unwrap
                PeerThreadMessage::AppendEntries(entry) => self.send_append_entries(entry),
                PeerThreadMessage::RequestVote(vote) => self.send_request_vote(vote)
            }
        }
    }
}

// Store's the state that the server is currently in along with the current_term
// and current_id. This fields should all share a lock.
struct ServerState {
    current_state: State,
    current_term: u64,
    current_id: u64
}

pub struct Server {
    state: Arc<Mutex<ServerState>>,
    log: Arc<Mutex<Log>>,
    peers: Vec<PeerHandle>,
    addr: SocketAddr,
    last_leader_contact: Instant,
    voted_for: Option<SocketAddr>
}

///
/// Starts up a new raft server with the given config.
/// This is mostly just a bootstrapper for now. It probably won't end up in the public API
/// As of right now this function does not return. It just runs the state machine as long as it's
/// in a live thread.
///
pub fn start_server(config: Config) -> ! {
    let (tx, rx) = channel();
    let mut server = Server::new(config, tx).unwrap();

    // The server starts up in a follower state. Set a timeout to become a candidate.

    loop {
        match server.state.current_state {
            State::FOLLOWER => {
                let btwn = Range::new(ELECTION_TIMEOUT_MIN, ELECTION_TIMEOUT_MAX);
                let mut range = rand::thread_rng();
                let timeout = Duration::from_millis(btwn.ind_sample(&mut range));
                thread::sleep(timeout);

                let now = Instant::now();
                let last_leader_contact = server.last_leader_contact;
                if now.duration_since(last_leader_contact) >= timeout {
                    // we have not heard from the leader for one timeout duration.
                    // start an election
                    server.start_election();
                }
            },
            State::CANDIDATE => {
                server.start_election();
                unimplemented!()
            },
            State::LEADER => {
                // sleep and then send a hearbeat?
                unimplemented!()
            }
        }
    }
}

impl Server {
    fn new (config: Config, tx: Sender<PeerThreadMessage>) -> Result<Server, IoError> {
        let addr = config.addr;
        // 1. Start RPC request handlers
        let append_entries_handler: Box<RpcObject> = Box::new(AppendEntriesHandler {});
        let services = vec![
            (1, append_entries_handler),
        ];
        let mut server = RpcServer::new_with_services(services);
        try!(
            server.bind((config.addr.ip(), config.addr.port()))
            .and_then(|_| {
                server.repl()
            })
        );

        // 2. Start peer threads.
        let peers = config.cluster.into_iter()
            .filter(move |x| *x != addr) // filter all computers that aren't me
            .map(move |x| Peer::start(x, tx.clone()))
            .collect::<Vec<PeerHandle>>();

        let log = Arc::new(Mutex::new(MemoryLog::new()));

        let state = Arc::new(Mutex::new(ServerState {
            current_state: State::FOLLOWER,
            current_term: 0,
            current_id: 0
        }));

        // 3. Construct server state object.
        Ok(Server {
            state: state,
            log: log,
            peers: peers,
            addr: addr,
            voted_for: None,
            last_leader_contact: Instant::now()
        })
    }

    ///
    /// Starts a new election by requesting votes from all peers
    /// If the election is successful then the server transitions into the LEADER state
    /// Otherwise the leader stays in the candidate state.
    /// The assumption is that the caller will start another election
    ///
    fn start_election(&mut self) {
        debug_assert!(self.state == State::CANDIDATE);
        // tell each peer to send out RequestToVote RPCs
        //let
        unimplemented!();
    }
}

struct AppendEntriesHandler {}

impl RpcObject for AppendEntriesHandler {
    fn handle_rpc (&self, params: capnp::any_pointer::Reader, result: capnp::any_pointer::Builder)
        -> Result<(), RpcError>
    {
        // TODO: If this is a valid rpc from the leader, update last_leader_contact

        // TODO: If we're in the CANDIDATE state and this leader's term is >= our current term
        //

        // TODO (syd) implement
        // 1. Ensure prevLogIndex matches our own.
        // 2. Append outstanding log entries.
        // 3. Construct reply.
        params.get_as::<append_entries::Reader>()
           .map(|append_entries| {
               result.init_as::<append_entries_reply::Builder>().set_success(true);
           })
           .map_err(RpcError::Capnp)
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use neb::client::{Client as NebClient, NebClientError};
use neb::server::{ServerOptions, NebServer, ServerError};

pub mod general;
pub mod schema;
pub mod traversal;

pub enum MorpheusServerErrors {
    ServerError(ServerError),
    ClientError(NebClientError)
}

pub struct MorpheusServer {
    neb_server: Arc<NebServer>,
    neb_client: Arc<NebClient>
}

impl MorpheusServer {
    pub fn new(opts: &ServerOptions)
        -> Result<Arc<MorpheusServer>, MorpheusServerErrors> {
        let neb_server = match NebServer::new(opts) {
            Ok(server) => server,
            Err(e) => return Err(MorpheusServerErrors::ServerError(e))
        };
        let neb_client = match NebClient::new(
            &neb_server.rpc, &opts.meta_members,
            &opts.group_name) {
            Ok(client) => Arc::new(client),
            Err(e) => return Err(MorpheusServerErrors::ClientError(e))
        };
        Ok(Arc::new(MorpheusServer {
            neb_server: neb_server,
            neb_client: neb_client,
        }))
    }
}<commit_msg>link schema service with server<commit_after>use std::sync::Arc;
use bifrost::raft::state_machine::master::ExecError;
use neb::client::{Client as NebClient, NebClientError};
use neb::server::{ServerOptions, NebServer, ServerError};

pub mod general;
pub mod schema;
pub mod traversal;

pub enum MorpheusServerError {
    ServerError(ServerError),
    ClientError(NebClientError),
    InitSchemaError(ExecError)
}

pub struct MorpheusServer {
    neb_server: Arc<NebServer>,
    neb_client: Arc<NebClient>
}

impl MorpheusServer {
    pub fn new(opts: &ServerOptions)
        -> Result<Arc<MorpheusServer>, MorpheusServerError> {
        let neb_server = match NebServer::new(opts) {
            Ok(server) => server,
            Err(e) => return Err(MorpheusServerError::ServerError(e))
        };
        let neb_client = match NebClient::new(
            &neb_server.rpc, &opts.meta_members,
            &opts.group_name) {
            Ok(client) => Arc::new(client),
            Err(e) => return Err(MorpheusServerError::ClientError(e))
        };
        if opts.is_meta {
            if let &Some(ref raft_service) = &neb_server.raft_service {
                schema::SchemaContainer::new_meta_service(raft_service);
            } else {
                panic!("raft service should be ready for meta server");
            }
        }
        let schema_container = match schema::SchemaContainer::new_client(&neb_client.raft_client) {
            Ok(container) => container,
            Err(e) => return Err(MorpheusServerError::InitSchemaError(e))
        };
        Ok(Arc::new(MorpheusServer {
            neb_server: neb_server,
            neb_client: neb_client,
        }))
    }
}<|endoftext|>


<commit_before>use krate::Crate;
use schema::badges;
use util::CargoResult;

use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use serde_json;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", tag = "badge_type", content = "attributes")]
pub enum Badge {
    TravisCi {
        repository: String,
        branch: Option<String>,
    },
    Appveyor {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "gitlab")]
    GitLab {
        repository: String,
        branch: Option<String>,
    },
    CircleCi {
        repository: String,
        branch: Option<String>,
    },
    IsItMaintainedIssueResolution { repository: String },
    IsItMaintainedOpenIssues { repository: String },
    Codecov {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    Coveralls {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "actively-developed")]
    ActivelyDeveloped {
        repository: String, branch: Option<String>,
    },
    #[serde(rename = "passively-maintained")]
    PassivelyMaintained {
        repository: String, branch: Option<String>,
    },
    #[serde(rename = "as-is")]
    AsIs {
        repository: String, branch: Option<String>,
    },
    #[serde(rename = "none")]
    None {
        repository: String, branch: Option<String>,
    },
    #[serde(rename = "experimental")]
    Experimental {
        repository: String, branch: Option<String>,
    },
    #[serde(rename = "looking-for-maintainer")]
    LookingForMaintainer {
        repository: String, branch: Option<String>,
    },
    #[serde(rename = "deprecated")]
    Deprecated {
        repository: String, branch: Option<String>,
    }
}

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl Queryable<badges::SqlType, Pg> for Badge {
    type Row = (i32, String, serde_json::Value);

    fn build((_, badge_type, attributes): Self::Row) -> Self {
        let json = json!({"badge_type": badge_type, "attributes": attributes});
        serde_json::from_value(json).expect("Invalid CI badge in the database")
    }
}

impl Badge {
    pub fn encodable(self) -> EncodableBadge {
        serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
    }

    pub fn update_crate<'a>(
        conn: &PgConnection,
        krate: &Crate,
        badges: Option<&'a HashMap<String, HashMap<String, String>>>,
    ) -> CargoResult<Vec<&'a str>> {
        use diesel::{insert, delete};

        #[derive(Insertable)]
        #[table_name = "badges"]
        struct NewBadge<'a> {
            crate_id: i32,
            badge_type: &'a str,
            attributes: serde_json::Value,
        }

        let mut invalid_badges = vec![];
        let mut new_badges = vec![];

        if let Some(badges) = badges {
            for (k, v) in badges {
                let attributes_json = serde_json::to_value(v).unwrap();

                let json = json!({"badge_type": k, "attributes": attributes_json});
                if serde_json::from_value::<Badge>(json).is_ok() {
                    new_badges.push(NewBadge {
                        crate_id: krate.id,
                        badge_type: &**k,
                        attributes: attributes_json,
                    });
                } else {
                    invalid_badges.push(&**k);
                }
            }
        }

        conn.transaction(|| {
            delete(badges::table.filter(badges::crate_id.eq(krate.id)))
                .execute(conn)?;
            insert(&new_badges).into(badges::table).execute(conn)?;
            Ok(invalid_badges)
        })
    }
}
<commit_msg>add new enum MaintenanceValue<commit_after>use krate::Crate;
use schema::badges;
use util::CargoResult;

use diesel::pg::{Pg, PgConnection};
use diesel::prelude::*;
use serde_json;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case", tag = "badge_type", content = "attributes")]
pub enum Badge {
    TravisCi {
        repository: String,
        branch: Option<String>,
    },
    Appveyor {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "gitlab")]
    GitLab {
        repository: String,
        branch: Option<String>,
    },
    CircleCi {
        repository: String,
        branch: Option<String>,
    },
    IsItMaintainedIssueResolution { repository: String },
    IsItMaintainedOpenIssues { repository: String },
    Codecov {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    Coveralls {
        repository: String,
        branch: Option<String>,
        service: Option<String>,
    },
    #[serde(rename = "maintenance")]
    Maintenance { value: MaintenanceValue },
}

#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
#[serde(tag = "badge_type", content = "attributes")]
pub enum MaintenanceValue {
    #[serde(rename = "actively-developed")]
    ActivelyDeveloped,

    #[serde(rename = "passively-maintained")]
    PassivelyMaintained,

    #[serde(rename = "as-is")]
    AsIs,

    #[serde(rename = "none")]
    None,

    #[serde(rename = "experimental")]
    Experimental,

    #[serde(rename = "looking-for-maintainer")]
    LookingForMaintainer,

    #[serde(rename = "deprecated")]
    Deprecated,
}

#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct EncodableBadge {
    pub badge_type: String,
    pub attributes: HashMap<String, Option<String>>,
}

impl Queryable<badges::SqlType, Pg> for Badge {
    type Row = (i32, String, serde_json::Value);

    fn build((_, badge_type, attributes): Self::Row) -> Self {
        let json = json!({"badge_type": badge_type, "attributes": attributes});
        serde_json::from_value(json).expect("Invalid CI badge in the database")
    }
}

impl Badge {
    pub fn encodable(self) -> EncodableBadge {
        serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
    }

    pub fn update_crate<'a>(
        conn: &PgConnection,
        krate: &Crate,
        badges: Option<&'a HashMap<String, HashMap<String, String>>>,
    ) -> CargoResult<Vec<&'a str>> {
        use diesel::{insert, delete};

        #[derive(Insertable)]
        #[table_name = "badges"]
        struct NewBadge<'a> {
            crate_id: i32,
            badge_type: &'a str,
            attributes: serde_json::Value,
        }

        let mut invalid_badges = vec![];
        let mut new_badges = vec![];

        if let Some(badges) = badges {
            for (k, v) in badges {
                let attributes_json = serde_json::to_value(v).unwrap();

                let json = json!({"badge_type": k, "attributes": attributes_json});
                if serde_json::from_value::<Badge>(json).is_ok() {
                    new_badges.push(NewBadge {
                        crate_id: krate.id,
                        badge_type: &**k,
                        attributes: attributes_json,
                    });
                } else {
                    invalid_badges.push(&**k);
                }
            }
        }

        conn.transaction(|| {
            delete(badges::table.filter(badges::crate_id.eq(krate.id)))
                .execute(conn)?;
            insert(&new_badges).into(badges::table).execute(conn)?;
            Ok(invalid_badges)
        })
    }
}
<|endoftext|>


<commit_before>use chrono::{DateTime, FixedOffset};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use model::*;

#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;

pub trait BanOptions {
    fn dmd(&self) -> u8 { 0 }
    fn reason(&self) -> &str { "" }
}

impl BanOptions for u8 {
    fn dmd(&self) -> u8 { *self }
}

impl BanOptions for str {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for &'a str {
    fn reason(&self) -> &str { self }
}

impl BanOptions for String {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for (u8, &'a str) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { self.1 }
}

impl BanOptions for (u8, String) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { &self.1 }
}

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: GuildId,
    /// Timestamp representing the date when the member joined.
    pub joined_at: Option<DateTime<FixedOffset>>,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with = "deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

#[cfg(feature = "model")]
impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            },
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn ban<BO: BanOptions>(&self, ban_options: BO) -> Result<()> {
        let dmd = ban_options.dmd();
        if dmd > 7 {
            return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
        }

        let reason = ban_options.reason();

        if reason.len() > 512 {
            return Err(Error::ExceededLimit(reason.to_string(), 512));
        }

        http::ban_user(
            self.guild_id.0,
            self.user.read().unwrap().id.0,
            dmd,
            &*reason,
        )
    }

    /// Determines the member's colour.
    #[cfg(all(feature = "cache", feature = "utils"))]
    pub fn colour(&self) -> Option<Colour> {
        let cache = CACHE.read().unwrap();
        let guild = try_opt!(cache.guilds.get(&self.guild_id)).read().unwrap();

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles
            .iter()
            .find(|r| r.colour.0 != default.0)
            .map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!(
            "{}#{}",
            self.display_name(),
            self.user.read().unwrap().discriminator
        )
    }

    /// Edits the member with the given data. See [`Guild::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Guild::edit_member`]: ../model/struct.Guild.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature = "cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let map = f(EditMember::default()).0;

        http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Model(ModelError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        #[cfg(feature = "cache")]
        {
            let req = Permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&self.guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Model(ModelError::InvalidPermissions(req)));
            }
        }

        self.guild_id.kick(self.user.read().unwrap().id)
    }

    /// Returns the permissions for the member.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assuming there's a `member` variable gotten from anything.
    /// println!("The permission bits for the member are: {}",
    /// member.permissions().expect("permissions").bits);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
    /// found in the cache.
    ///
    /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
    #[cfg(feature = "cache")]
    pub fn permissions(&self) -> Result<Permissions> {
        let guild = match self.guild_id.find() {
            Some(guild) => guild,
            None => return Err(From::from(ModelError::GuildNotFound)),
        };

        let guild = guild.read().unwrap();

        let default_channel = match guild.default_channel() {
            Some(dc) => dc,
            None => return Err(From::from(ModelError::ItemMissing)),
        };

        Ok(
            guild
                .permissions_for(default_channel.id, self.user.read().unwrap().id),
        )
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature = "cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        self
            .guild_id
            .find()
            .map(|g| g
                .read()
                .unwrap()
                .roles
                .values()
                .filter(|role| self.roles.contains(&role.id))
                .cloned()
                .collect())
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn unban(&self) -> Result<()> {
        http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<commit_msg>Add some docs to `BanOptions`<commit_after>use chrono::{DateTime, FixedOffset};
use std::fmt::{Display, Formatter, Result as FmtResult};
use super::deserialize_sync_user;
use model::*;

#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(all(feature = "cache", feature = "model"))]
use internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use http;
#[cfg(all(feature = "builder", feature = "cache", feature = "model"))]
use builder::EditMember;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use utils::Colour;

/// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`.
pub trait BanOptions {
    fn dmd(&self) -> u8 { 0 }
    fn reason(&self) -> &str { "" }
}

impl BanOptions for u8 {
    fn dmd(&self) -> u8 { *self }
}

impl BanOptions for str {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for &'a str {
    fn reason(&self) -> &str { self }
}

impl BanOptions for String {
    fn reason(&self) -> &str { self }
}

impl<'a> BanOptions for (u8, &'a str) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { self.1 }
}

impl BanOptions for (u8, String) {
    fn dmd(&self) -> u8 { self.0 }

    fn reason(&self) -> &str { &self.1 }
}

/// Information about a member of a guild.
#[derive(Clone, Debug, Deserialize)]
pub struct Member {
    /// Indicator of whether the member can hear in voice channels.
    pub deaf: bool,
    /// The unique Id of the guild that the member is a part of.
    pub guild_id: GuildId,
    /// Timestamp representing the date when the member joined.
    pub joined_at: Option<DateTime<FixedOffset>>,
    /// Indicator of whether the member can speak in voice channels.
    pub mute: bool,
    /// The member's nickname, if present.
    ///
    /// Can't be longer than 32 characters.
    pub nick: Option<String>,
    /// Vector of Ids of [`Role`]s given to the member.
    pub roles: Vec<RoleId>,
    /// Attached User struct.
    #[serde(deserialize_with = "deserialize_sync_user")]
    pub user: Arc<RwLock<User>>,
}

#[cfg(feature = "model")]
impl Member {
    /// Adds a [`Role`] to the member, editing its roles in-place if the request
    /// was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::add_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.push(role_id);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Adds one or multiple [`Role`]s to the member, editing
    /// its roles in-place if the request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn add_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.extend_from_slice(role_ids);

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.retain(|r| !role_ids.contains(r));

                Err(why)
            },
        }
    }

    /// Ban the member from its guild, deleting the last X number of
    /// days' worth of messages.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild could not be
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    ///
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn ban<BO: BanOptions>(&self, ban_options: BO) -> Result<()> {
        let dmd = ban_options.dmd();
        if dmd > 7 {
            return Err(Error::Model(ModelError::DeleteMessageDaysAmount(dmd)));
        }

        let reason = ban_options.reason();

        if reason.len() > 512 {
            return Err(Error::ExceededLimit(reason.to_string(), 512));
        }

        http::ban_user(
            self.guild_id.0,
            self.user.read().unwrap().id.0,
            dmd,
            &*reason,
        )
    }

    /// Determines the member's colour.
    #[cfg(all(feature = "cache", feature = "utils"))]
    pub fn colour(&self) -> Option<Colour> {
        let cache = CACHE.read().unwrap();
        let guild = try_opt!(cache.guilds.get(&self.guild_id)).read().unwrap();

        let mut roles = self.roles
            .iter()
            .filter_map(|role_id| guild.roles.get(role_id))
            .collect::<Vec<&Role>>();
        roles.sort_by(|a, b| b.cmp(a));

        let default = Colour::default();

        roles
            .iter()
            .find(|r| r.colour.0 != default.0)
            .map(|r| r.colour)
    }

    /// Calculates the member's display name.
    ///
    /// The nickname takes priority over the member's username if it exists.
    #[inline]
    pub fn display_name(&self) -> Cow<String> {
        self.nick
            .as_ref()
            .map(Cow::Borrowed)
            .unwrap_or_else(|| Cow::Owned(self.user.read().unwrap().name.clone()))
    }

    /// Returns the DiscordTag of a Member, taking possible nickname into account.
    #[inline]
    pub fn distinct(&self) -> String {
        format!(
            "{}#{}",
            self.display_name(),
            self.user.read().unwrap().discriminator
        )
    }

    /// Edits the member with the given data. See [`Guild::edit_member`] for
    /// more information.
    ///
    /// See [`EditMember`] for the permission(s) required for separate builder
    /// methods, as well as usage of this.
    ///
    /// [`Guild::edit_member`]: ../model/struct.Guild.html#method.edit_member
    /// [`EditMember`]: ../builder/struct.EditMember.html
    #[cfg(feature = "cache")]
    pub fn edit<F: FnOnce(EditMember) -> EditMember>(&self, f: F) -> Result<()> {
        let map = f(EditMember::default()).0;

        http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map)
    }

    /// Kick the member from the guild.
    ///
    /// **Note**: Requires the [Kick Members] permission.
    ///
    /// # Examples
    ///
    /// Kick a member from its guild:
    ///
    /// ```rust,ignore
    /// // assuming a `member` has already been bound
    /// match member.kick() {
    ///     Ok(()) => println!("Successfully kicked member"),
    ///     Err(Error::Model(ModelError::GuildNotFound)) => {
    ///         println!("Couldn't determine guild of member");
    ///     },
    ///     Err(Error::Model(ModelError::InvalidPermissions(missing_perms))) => {
    ///         println!("Didn't have permissions; missing: {:?}", missing_perms);
    ///     },
    ///     _ => {},
    /// }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the Id of the member's guild
    /// could not be determined.
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform the kick.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Kick Members]: permissions/constant.KICK_MEMBERS.html
    pub fn kick(&self) -> Result<()> {
        #[cfg(feature = "cache")]
        {
            let req = Permissions::KICK_MEMBERS;

            let has_perms = CACHE
                .read()
                .unwrap()
                .guilds
                .get(&self.guild_id)
                .map(|guild| guild.read().unwrap().has_perms(req));

            if let Some(Ok(false)) = has_perms {
                return Err(Error::Model(ModelError::InvalidPermissions(req)));
            }
        }

        self.guild_id.kick(self.user.read().unwrap().id)
    }

    /// Returns the permissions for the member.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assuming there's a `member` variable gotten from anything.
    /// println!("The permission bits for the member are: {}",
    /// member.permissions().expect("permissions").bits);
    /// ```
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::GuildNotFound`] if the guild the member's in could not be
    /// found in the cache.
    ///
    /// And/or returns [`ModelError::ItemMissing`] if the "default channel" of the guild is not
    /// found.
    ///
    /// [`ModelError::GuildNotFound`]: enum.ModelError.html#variant.GuildNotFound
    /// [`ModelError::ItemMissing`]: enum.ModelError.html#variant.ItemMissing
    #[cfg(feature = "cache")]
    pub fn permissions(&self) -> Result<Permissions> {
        let guild = match self.guild_id.find() {
            Some(guild) => guild,
            None => return Err(From::from(ModelError::GuildNotFound)),
        };

        let guild = guild.read().unwrap();

        let default_channel = match guild.default_channel() {
            Some(dc) => dc,
            None => return Err(From::from(ModelError::ItemMissing)),
        };

        Ok(
            guild
                .permissions_for(default_channel.id, self.user.read().unwrap().id),
        )
    }

    /// Removes a [`Role`] from the member, editing its roles in-place if the
    /// request was successful.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_role<R: Into<RoleId>>(&mut self, role_id: R) -> Result<()> {
        let role_id = role_id.into();

        if !self.roles.contains(&role_id) {
            return Ok(());
        }

        match http::remove_member_role(self.guild_id.0, self.user.read().unwrap().id.0, role_id.0) {
            Ok(()) => {
                self.roles.retain(|r| r.0 != role_id.0);

                Ok(())
            },
            Err(why) => Err(why),
        }
    }

    /// Removes one or multiple [`Role`]s from the member.
    ///
    /// **Note**: Requires the [Manage Roles] permission.
    ///
    /// [`Role`]: struct.Role.html
    /// [Manage Roles]: permissions/constant.MANAGE_ROLES.html
    #[cfg(feature = "cache")]
    pub fn remove_roles(&mut self, role_ids: &[RoleId]) -> Result<()> {
        self.roles.retain(|r| !role_ids.contains(r));

        let map = EditMember::default().roles(&self.roles).0;

        match http::edit_member(self.guild_id.0, self.user.read().unwrap().id.0, &map) {
            Ok(()) => Ok(()),
            Err(why) => {
                self.roles.extend_from_slice(role_ids);

                Err(why)
            },
        }
    }

    /// Retrieves the full role data for the user's roles.
    ///
    /// This is shorthand for manually searching through the CACHE.
    ///
    /// If role data can not be found for the member, then `None` is returned.
    #[cfg(feature = "cache")]
    pub fn roles(&self) -> Option<Vec<Role>> {
        self
            .guild_id
            .find()
            .map(|g| g
                .read()
                .unwrap()
                .roles
                .values()
                .filter(|role| self.roles.contains(&role.id))
                .cloned()
                .collect())
    }

    /// Unbans the [`User`] from the guild.
    ///
    /// **Note**: Requires the [Ban Members] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have permission to perform bans.
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`User`]: struct.User.html
    /// [Ban Members]: permissions/constant.BAN_MEMBERS.html
    #[cfg(feature = "cache")]
    pub fn unban(&self) -> Result<()> {
        http::remove_ban(self.guild_id.0, self.user.read().unwrap().id.0)
    }
}

impl Display for Member {
    /// Mentions the user so that they receive a notification.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// // assumes a `member` has already been bound
    /// println!("{} is a member!", member);
    /// ```
    ///
    // This is in the format of `<@USER_ID>`.
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        Display::fmt(&self.user.read().unwrap().mention(), f)
    }
}
<|endoftext|>


<commit_before>extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::spanned::Spanned;

/// This attribute generates a Lucet hostcall from a standalone Rust function that takes a `&mut
/// Vmctx` as its first argument.
///
/// It is important to use this attribute for hostcalls, rather than exporting them
/// directly. Otherwise the behavior of instance termination and timeouts are
/// undefined. Additionally, the attribute makes the resulting function `unsafe extern "C"`
/// regardless of how the function is defined, as this ABI is required for all hostcalls.
///
/// In most cases, you will want to also provide the `#[no_mangle]` attribute and `pub` visibility
/// in order for the hostcall to be exported from the final executable.
///
/// ```ignore
/// #[lucet_hostcall]
/// #[no_mangle]
/// pub fn yield_5(vmctx: &mut Vmctx) {
///     vmctx.yield_val(5);
/// }
/// ```
///
/// Note that `lucet-runtime` must be a dependency of any crate where this attribute is used, and it
/// may not be renamed (this restriction may be lifted once [this
/// issue](https://github.com/rust-lang/rust/issues/54363) is resolved).
#[proc_macro_attribute]
pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream {
    // determine whether we need to import from `lucet_runtime_internals`; this is useful if we want
    // to define a hostcall for a target (or tests, more concretely) that doesn't depend on
    // `lucet-runtime`
    let in_internals = std::env::var("CARGO_PKG_NAME").unwrap() == "lucet-runtime-internals";

    let mut hostcall = syn::parse_macro_input!(item as syn::ItemFn);
    let hostcall_ident = hostcall.sig.ident.clone();

    // use the same attributes and visibility as the impl hostcall
    let attrs = hostcall.attrs.clone();
    let vis = hostcall.vis.clone();

    // remove #[no_mangle] from the attributes of the impl hostcall if it's there
    hostcall.attrs = attrs
        .iter()
        .filter(|attr| !attr.path.is_ident("no_mangle"))
        .cloned()
        .collect();
    // make the impl hostcall private
    hostcall.vis = syn::Visibility::Inherited;

    // modify the type signature of the exported raw hostcall based on the original signature
    let mut raw_sig = hostcall.sig.clone();

    // hostcalls are always unsafe
    raw_sig.unsafety = Some(syn::Token![unsafe](raw_sig.span()));

    // hostcalls are always extern "C"
    raw_sig.abi = Some(syn::parse_quote!(extern "C"));

    let vmctx_mod = if in_internals {
        quote! { lucet_runtime_internals::vmctx }
    } else {
        quote! { lucet_runtime::vmctx }
    };

    // replace the first argument to the raw hostcall with the vmctx pointer
    if let Some(arg0) = raw_sig.inputs.iter_mut().nth(0) {
        let lucet_vmctx: syn::FnArg = syn::parse_quote!(vmctx_raw: *mut #vmctx_mod::lucet_vmctx);
        *arg0 = lucet_vmctx;
    }

    // the args after the first to provide to the hostcall impl
    let impl_args = hostcall
        .sig
        .inputs
        .iter()
        .skip(1)
        .map(|arg| match arg {
            syn::FnArg::Receiver(_) => {
                // this case is an error, but we produce some valid rust code anyway so that the
                // compiler can produce a more meaningful error message at a later point
                let s = syn::Token![self](arg.span());
                quote!(#s)
            }
            syn::FnArg::Typed(syn::PatType { pat, .. }) => quote!(#pat),
        })
        .collect::<Vec<_>>();

    let termination_details = if in_internals {
        quote! { lucet_runtime_internals::instance::TerminationDetails }
    } else {
        quote! { lucet_runtime::TerminationDetails }
    };

    let raw_hostcall = quote! {
        #(#attrs)*
        #vis
        #raw_sig {
            #[inline(always)]
            #hostcall

            let mut vmctx = #vmctx_mod::Vmctx::from_raw(vmctx_raw);
            #vmctx_mod::VmctxInternal::instance_mut(&mut vmctx).uninterruptable(|| {
                let res = std::panic::catch_unwind(move || {
                    #hostcall_ident(&mut #vmctx_mod::Vmctx::from_raw(vmctx_raw), #(#impl_args),*)
                });
                match res {
                    Ok(res) => res,
                    Err(e) => {
                        match e.downcast::<#termination_details>() {
                            Ok(details) => {
                                #vmctx_mod::Vmctx::from_raw(vmctx_raw).terminate_no_unwind(*details)
                            },
                            Err(e) => std::panic::resume_unwind(e),
                        }
                    }
                }
            })
        }
    };
    raw_hostcall.into()
}
<commit_msg>remove some unnecessary cloning in `#[lucet_hostcall]`<commit_after>extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::spanned::Spanned;

/// This attribute generates a Lucet hostcall from a standalone Rust function that takes a `&mut
/// Vmctx` as its first argument.
///
/// It is important to use this attribute for hostcalls, rather than exporting them
/// directly. Otherwise the behavior of instance termination and timeouts are
/// undefined. Additionally, the attribute makes the resulting function `unsafe extern "C"`
/// regardless of how the function is defined, as this ABI is required for all hostcalls.
///
/// In most cases, you will want to also provide the `#[no_mangle]` attribute and `pub` visibility
/// in order for the hostcall to be exported from the final executable.
///
/// ```ignore
/// #[lucet_hostcall]
/// #[no_mangle]
/// pub fn yield_5(vmctx: &mut Vmctx) {
///     vmctx.yield_val(5);
/// }
/// ```
///
/// Note that `lucet-runtime` must be a dependency of any crate where this attribute is used, and it
/// may not be renamed (this restriction may be lifted once [this
/// issue](https://github.com/rust-lang/rust/issues/54363) is resolved).
#[proc_macro_attribute]
pub fn lucet_hostcall(_attr: TokenStream, item: TokenStream) -> TokenStream {
    // determine whether we need to import from `lucet_runtime_internals`; this is useful if we want
    // to define a hostcall for a target (or tests, more concretely) that doesn't depend on
    // `lucet-runtime`
    let in_internals = std::env::var("CARGO_PKG_NAME").unwrap() == "lucet-runtime-internals";

    let mut hostcall = syn::parse_macro_input!(item as syn::ItemFn);
    let hostcall_ident = hostcall.sig.ident.clone();

    // use the same attributes and visibility as the impl hostcall
    let attrs = hostcall.attrs.clone();
    let vis = hostcall.vis.clone();

    // remove #[no_mangle] from the attributes of the impl hostcall if it's there
    hostcall
        .attrs
        .retain(|attr| !attr.path.is_ident("no_mangle"));
    // make the impl hostcall private
    hostcall.vis = syn::Visibility::Inherited;

    // modify the type signature of the exported raw hostcall based on the original signature
    let mut raw_sig = hostcall.sig.clone();

    // hostcalls are always unsafe
    raw_sig.unsafety = Some(syn::Token![unsafe](raw_sig.span()));

    // hostcalls are always extern "C"
    raw_sig.abi = Some(syn::parse_quote!(extern "C"));

    let vmctx_mod = if in_internals {
        quote! { lucet_runtime_internals::vmctx }
    } else {
        quote! { lucet_runtime::vmctx }
    };

    // replace the first argument to the raw hostcall with the vmctx pointer
    if let Some(arg0) = raw_sig.inputs.iter_mut().nth(0) {
        let lucet_vmctx: syn::FnArg = syn::parse_quote!(vmctx_raw: *mut #vmctx_mod::lucet_vmctx);
        *arg0 = lucet_vmctx;
    }

    // the args after the first to provide to the hostcall impl
    let impl_args = hostcall
        .sig
        .inputs
        .iter()
        .skip(1)
        .map(|arg| match arg {
            syn::FnArg::Receiver(_) => {
                // this case is an error, but we produce some valid rust code anyway so that the
                // compiler can produce a more meaningful error message at a later point
                let s = syn::Token![self](arg.span());
                quote!(#s)
            }
            syn::FnArg::Typed(syn::PatType { pat, .. }) => quote!(#pat),
        })
        .collect::<Vec<_>>();

    let termination_details = if in_internals {
        quote! { lucet_runtime_internals::instance::TerminationDetails }
    } else {
        quote! { lucet_runtime::TerminationDetails }
    };

    let raw_hostcall = quote! {
        #(#attrs)*
        #vis
        #raw_sig {
            #[inline(always)]
            #hostcall

            let mut vmctx = #vmctx_mod::Vmctx::from_raw(vmctx_raw);
            #vmctx_mod::VmctxInternal::instance_mut(&mut vmctx).uninterruptable(|| {
                let res = std::panic::catch_unwind(move || {
                    #hostcall_ident(&mut #vmctx_mod::Vmctx::from_raw(vmctx_raw), #(#impl_args),*)
                });
                match res {
                    Ok(res) => res,
                    Err(e) => {
                        match e.downcast::<#termination_details>() {
                            Ok(details) => {
                                #vmctx_mod::Vmctx::from_raw(vmctx_raw).terminate_no_unwind(*details)
                            },
                            Err(e) => std::panic::resume_unwind(e),
                        }
                    }
                }
            })
        }
    };
    raw_hostcall.into()
}
<|endoftext|>


<commit_before>//! Read points from .sdf full waveform files.
//!
//! Our sdf library contains some logic to do discretization of waveforms, so we just use that
//! rather than processing the waveforms ourselves.

use std::ffi::OsStr;
use std::path::Path;
use std::u32;

use sdf;

use Result;
use error::Error;
use point::{Intensity, Point};
use source::{FileSource, Source};

impl Source for sdf::File {
    fn source(&mut self, want: usize) -> Result<Option<Vec<Point>>> {
        let mut points = Vec::with_capacity(want);
        let ref file_info = try!(self.info());
        try!(self.reindex());
        loop {
            match self.read() {
                Ok(ref record) => {
                    points.append(&mut try!(sdf::convert::discretize(record, file_info))
                                           .into_iter()
                                           .map(|p| Point::from(p))
                                           .collect());
                    if points.len() > want {
                        break;
                    }
                }
                Err(sdf::Error::EndOfFile(_)) => {
                    break;
                }
                Err(err) => return Err(Error::from(err)),
            }
        }
        if points.is_empty() {
            Ok(None)
        } else {
            Ok(Some(points))
        }
    }

    fn source_len(&mut self) -> Option<usize> {
        if self.reindex().is_err() {
            return None;
        }
        if self.seek(0).is_err() {
            return None;
        }
        let start = match self.tell() {
            Ok(n) => n,
            Err(_) => return None,
        };
        if self.seek(u32::MAX).is_err() {
            return None;
        }
        let end = match self.tell() {
            Ok(n) => n,
            Err(_) => return None,
        };
        Some((end - start) as usize)
    }
}

impl From<sdf::convert::Point> for Point {
    fn from(point: sdf::convert::Point) -> Point {
        Point {
            x: point.x as f64,
            y: point.y as f64,
            z: point.z as f64,
            intensity: Intensity::from_u16(point.peak.amplitude),
            return_number: Some(point.target as usize),
            number_of_returns: Some(point.num_target as usize),
            facet_number: Some(point.facet as u8),
            high_channel: Some(point.high_channel),
            // TODO this probably isn't always gps time
            gps_time: Some(point.time),
            ..Default::default()
        }
    }
}

impl FileSource for sdf::File {
    type Config = SdfConfig;
    fn open_file_source<P>(path: P, _: Self::Config) -> Result<Box<Source>>
        where P: AsRef<Path> + AsRef<OsStr>
    {
        let path = OsStr::new(&path);
        Ok(Box::new(try!(sdf::File::open(path.to_str().unwrap()))))
    }
}

/// Our decodable configuration.
#[derive(Clone, Copy, Debug, Default, RustcDecodable)]
pub struct SdfConfig;

#[cfg(test)]
mod tests {

    use sdf;

    use source::{Source, open_file_source};

    #[test]
    fn source_them_all() {
        let mut source = sdf::File::open("data/110630_174316.sdf").unwrap();
        let points = source.source(1000).unwrap().unwrap();
        assert!(points.len() >= 1000);
        source.remove_index().unwrap();
    }

    #[test]
    fn open_file_source_test() {
        let _ = open_file_source("data/110630_174316.sdf", None).unwrap();
    }
}
<commit_msg>Include scan angle in sdf source<commit_after>//! Read points from .sdf full waveform files.
//!
//! Our sdf library contains some logic to do discretization of waveforms, so we just use that
//! rather than processing the waveforms ourselves.

use std::ffi::OsStr;
use std::path::Path;
use std::u32;

use sdf;

use Result;
use error::Error;
use point::{Intensity, Point};
use source::{FileSource, Source};

impl Source for sdf::File {
    fn source(&mut self, want: usize) -> Result<Option<Vec<Point>>> {
        let mut points = Vec::with_capacity(want);
        let ref file_info = try!(self.info());
        try!(self.reindex());
        loop {
            match self.read() {
                Ok(ref record) => {
                    points.append(&mut try!(sdf::convert::discretize(record, file_info))
                                           .into_iter()
                                           .map(|p| Point::from(p))
                                           .collect());
                    if points.len() > want {
                        break;
                    }
                }
                Err(sdf::Error::EndOfFile(_)) => {
                    break;
                }
                Err(err) => return Err(Error::from(err)),
            }
        }
        if points.is_empty() {
            Ok(None)
        } else {
            Ok(Some(points))
        }
    }

    fn source_len(&mut self) -> Option<usize> {
        if self.reindex().is_err() {
            return None;
        }
        if self.seek(0).is_err() {
            return None;
        }
        let start = match self.tell() {
            Ok(n) => n,
            Err(_) => return None,
        };
        if self.seek(u32::MAX).is_err() {
            return None;
        }
        let end = match self.tell() {
            Ok(n) => n,
            Err(_) => return None,
        };
        Some((end - start) as usize)
    }
}

impl From<sdf::convert::Point> for Point {
    fn from(point: sdf::convert::Point) -> Point {
        Point {
            x: point.x as f64,
            y: point.y as f64,
            z: point.z as f64,
            scan_angle: Some(point.theta as f64),
            intensity: Intensity::from_u16(point.peak.amplitude),
            return_number: Some(point.target as usize),
            number_of_returns: Some(point.num_target as usize),
            facet_number: Some(point.facet as u8),
            high_channel: Some(point.high_channel),
            // TODO this probably isn't always gps time
            gps_time: Some(point.time),
            ..Default::default()
        }
    }
}

impl FileSource for sdf::File {
    type Config = SdfConfig;
    fn open_file_source<P>(path: P, _: Self::Config) -> Result<Box<Source>>
        where P: AsRef<Path> + AsRef<OsStr>
    {
        let path = OsStr::new(&path);
        Ok(Box::new(try!(sdf::File::open(path.to_str().unwrap()))))
    }
}

/// Our decodable configuration.
#[derive(Clone, Copy, Debug, Default, RustcDecodable)]
pub struct SdfConfig;

#[cfg(test)]
mod tests {

    use sdf;

    use source::{Source, open_file_source};

    #[test]
    fn source_them_all() {
        let mut source = sdf::File::open("data/110630_174316.sdf").unwrap();
        let points = source.source(1000).unwrap().unwrap();
        assert!(points.len() >= 1000);
        source.remove_index().unwrap();
    }

    #[test]
    fn open_file_source_test() {
        let _ = open_file_source("data/110630_174316.sdf", None).unwrap();
    }
}
<|endoftext|>


<commit_before>use super::command;

// An item on the chain
#[derive(Clone)]
pub enum Item<'a> {
    FatalCommand(String),
    NonFatalCommand(String),
    ResultProcessor(&'a Fn(&command::Result) -> command::Result),
    CommandModifier(&'a Fn(&command::Result, Option<&'a mut Item>) -> Option<&'a mut Item<'a>>)
}

pub struct CommandChain<'a> {
    pub commands: Vec<Item<'a>>,
    pub old_commands: Vec<Item<'a>>,
    pub result: Option<command::Result>
}

impl<'a> CommandChain<'a> {

    pub fn new() -> Self {
        CommandChain {
            commands: Vec::new(),
            old_commands: Vec::new(),
            result: None
        }
    }

    pub fn result_proc(&'a mut self, f: &'a Fn(&command::Result) -> command::Result) -> &'a mut CommandChain {
        self.commands.push(Item::ResultProcessor(f));
        self
    }

    pub fn cmd(&'a mut self, command_string: &str) -> &'a mut CommandChain {
        self.commands.push(Item::FatalCommand(String::from(command_string)));
        self
    }

    pub fn cmd_nonfatal(&'a mut self, command_string: &str) -> &'a mut CommandChain {
        self.commands.push(Item::NonFatalCommand(String::from(command_string)));
        self
    }

    fn run_command(cmd_str : &str) -> command::Result {
        let result = command::run_host_cmd(cmd_str);
        if result.success {
            info!("stdout:{}", result.stdout);
        } else {
            warn!("stderr:{}", result.stderr);
        }
        result
    }

    // Executes the chain and returns self, with vector reset
    pub fn execute(&'a mut self) -> CommandChain {
        for item in self.commands.iter() {
            match item {
                &Item::FatalCommand(ref s) => {
                    let result = CommandChain::run_command(s);
                    if !result.success {
                        self.result = Some(result);
                        break
                    }
                    self.result = Some(result);
                },
                &Item::NonFatalCommand(ref s) => {
                    let result = CommandChain::run_command(s);
                    self.result = Some(result);
                },
                &Item::ResultProcessor(f) => {
                    self.result = {
                        if let Some(ref mut curr_res) = self.result {
                            Some(f(&curr_res))
                        } else {
                            warn!("Executing ResultProcessor with no current result is a no-op!");
                            None
                        }
                    };
                },
                &Item::CommandModifier(f) => {
                    // TODO: implement me!
                }
            }
        }
        CommandChain {
            commands: Vec::new(),
            old_commands: self.commands.clone(),
            result: self.result.clone()
        }
    }
}
<commit_msg>so close<commit_after>use super::command;

// An item on the chain
#[derive(Clone)]
pub enum Item<'a> {
    FatalCommand(String),
    NonFatalCommand(String),
    ResultProcessor(&'a Fn(&command::Result) -> command::Result),
    CommandModifier(&'a Fn(&command::Result, Option<&'a mut Item>) -> Option<&'a mut Item<'a>>)
}

pub struct CommandChain<'a> {
    pub commands: Vec<Item<'a>>,
    pub old_commands: Vec<Item<'a>>,
    pub result: Option<command::Result>
}

impl<'a> CommandChain<'a> {

    pub fn new() -> Self {
        CommandChain {
            commands: Vec::new(),
            old_commands: Vec::new(),
            result: None
        }
    }

    pub fn result_proc(mut self, f: &'a Fn(&command::Result) -> command::Result) -> Self {
        self.commands.push(Item::ResultProcessor(f));
        self
    }

    pub fn cmd(mut self, command_string: &str) -> Self {
        self.commands.push(Item::FatalCommand(String::from(command_string)));
        self
    }

    pub fn cmd_nonfatal(mut self, command_string: &str) -> Self {
        self.commands.push(Item::NonFatalCommand(String::from(command_string)));
        self
    }

    fn run_command(cmd_str : &str) -> command::Result {
        let result = command::run_host_cmd(cmd_str);
        if result.success {
            info!("stdout:{}", result.stdout);
        } else {
            warn!("stderr:{}", result.stderr);
        }
        result
    }

    // Executes the chain and returns self, with vector reset
    pub fn execute(mut self) -> Self {
        for item in self.commands.iter() {
            match item {
                &Item::FatalCommand(ref s) => {
                    let result = CommandChain::run_command(s);
                    if !result.success {
                        self.result = Some(result);
                        break
                    }
                    self.result = Some(result);
                },
                &Item::NonFatalCommand(ref s) => {
                    let result = CommandChain::run_command(s);
                    self.result = Some(result);
                },
                &Item::ResultProcessor(f) => {
                    self.result = {
                        if let Some(ref mut curr_res) = self.result {
                            Some(f(&curr_res))
                        } else {
                            warn!("Executing ResultProcessor with no current result is a no-op!");
                            None
                        }
                    };
                },
                &Item::CommandModifier(f) => {
                    // TODO: implement me!
                }
            }
        }
        CommandChain {
            commands: Vec::new(),
            old_commands: self.commands.clone(),
            result: self.result.clone()
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::vec::Vec;

use byteorder::{ByteOrder, BigEndian};
use protobuf::{Message, MessageStatic};

use raft::errors::{Result, Error};

const MSG_HEADER_LEN: usize = 16;
const MSG_MAGIC: u16 = 0xdaf4;
const MSG_VERSION_V1: u16 = 1;

// Encodes message with message ID and protobuf body.
// Message contains header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Payload is a protobuf message.
pub fn encode_message<T: io::Write, M: Message>(w: &mut T, msg_id: u64, msg: &M) -> Result<()> {
    // Create a 16 bytes header and write it.
    let mut buf = vec!(0; MSG_HEADER_LEN);
    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    try!(msg.write_to_vec(&mut buf));

    // Set payload length here
    let payload_len = (buf.len() - MSG_HEADER_LEN) as u32;
    BigEndian::write_u32(&mut buf[4..8], payload_len);

    try!(w.write(&buf));

    Ok(())
}

// Decodes message with above encoded format, returns message ID.
pub fn decode_message<T: io::Read, M: Message>(r: &mut T, m: &mut M) -> Result<u64> {
    // First read 16 bytes header
    let mut header = [0; MSG_HEADER_LEN];
    // TODO: check exact read bytes number.
    try!(r.read(&mut header));

    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(Error::Other(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(Error::Other(format!("unsupported version {}, we need {} now",
                                        version,
                                        MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let msg_id: u64 = BigEndian::read_u64(&header[8..16]);
    let mut payload = vec![0;payload_len];

    let n = try!(r.read(&mut payload));
    try!(m.merge_from_bytes(&payload));

    Ok(msg_id)
}

#[cfg(test)]
mod tests {
    use bytes::{Buf, ByteBuf, MutByteBuf};

    use raft::codec::{encode_message, decode_message};
    use raft::raftpb::{Message, MessageType};
    use raft::errors::{Result, Error};

    #[test]
    fn test_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_message(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_message(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }
}
<commit_msg>raft: Address comment.<commit_after>use std::io;

use byteorder::{ByteOrder, BigEndian};
use protobuf::Message;

use raft::errors::{Result, Error};

const MSG_HEADER_LEN: usize = 16;
const MSG_MAGIC: u16 = 0xdaf4;
const MSG_VERSION_V1: u16 = 1;

// Encodes message with message ID and protobuf body.
// Message contains header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Payload is a protobuf message.
pub fn encode_message<T: io::Write, M: Message>(w: &mut T, msg_id: u64, msg: &M) -> Result<()> {
    // Create a 16 bytes header and write it.
    let mut buf = vec!(0; MSG_HEADER_LEN);
    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    try!(msg.write_to_vec(&mut buf));

    // Set payload length here
    let payload_len = (buf.len() - MSG_HEADER_LEN) as u32;
    BigEndian::write_u32(&mut buf[4..8], payload_len);

    try!(w.write(&buf));

    Ok(())
}

// Decodes message with above encoded format, returns message ID.
pub fn decode_message<T: io::Read, M: Message>(r: &mut T, m: &mut M) -> Result<u64> {
    // First read 16 bytes header
    let mut header = [0; MSG_HEADER_LEN];
    // TODO: check exact read bytes number.
    try!(r.read(&mut header));

    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(Error::Other(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(Error::Other(format!("unsupported version {}, we need {} now",
                                        version,
                                        MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let msg_id: u64 = BigEndian::read_u64(&header[8..16]);
    let mut payload = vec![0;payload_len];

    let n = try!(r.read(&mut payload));
    try!(m.merge_from_bytes(&payload));

    Ok(msg_id)
}

#[cfg(test)]
mod tests {
    use bytes::{Buf, ByteBuf, MutByteBuf};

    use raft::codec::{encode_message, decode_message};
    use raft::raftpb::{Message, MessageType};
    use raft::errors::{Result, Error};

    #[test]
    fn test_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_message(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_message(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }
}
<|endoftext|>


<commit_before>use crate::rank::Rank;
use std::ops::Not;

/// Represent a color.
#[derive(PartialOrd, PartialEq, Eq, Copy, Clone, Debug, Hash)]
pub enum Color {
    White,
    Black,
}

/// How many colors are there?
pub const NUM_COLORS: usize = 2;
/// List all colors
pub const ALL_COLORS: [Color; NUM_COLORS] = [Color::White, Color::Black];

impl Color {
    /// Convert the `Color` to a `usize` for table lookups.
    #[inline]
    pub fn to_index(&self) -> usize {
        *self as usize
    }

    /// Covert the `Color` to a rank, which reperesnts the starting position
    /// for that colors pieces.
    #[inline]
    pub fn to_my_backrank(&self) -> Rank {
        match *self {
            Color::White => Rank::First,
            Color::Black => Rank::Eighth,
        }
    }

    /// Convert a `Color` to my opponents backrank, which represents the starting position for the
    /// opponents pieces.
    #[inline]
    pub fn to_their_backrank(&self) -> Rank {
        match *self {
            Color::White => Rank::Eighth,
            Color::Black => Rank::First,
        }
    }

    /// Convert a `Color` to my second rank, which represents the starting position for my pawns.
    #[inline]
    pub fn to_second_rank(&self) -> Rank {
        match *self {
            Color::White => Rank::Second,
            Color::Black => Rank::Seventh,
        }
    }

    #[inline]
    pub fn to_fourth_rank(&self) -> Rank {
        match *self {
            Color::White => Rank::Fourth,
            Color::Black => Rank::Fifth,
        }
    }

    /// Convert a `Color` to my seventh rank, which represents the rank before pawn promotion.
    #[inline]
    pub fn to_seventh_rank(&self) -> Rank {
        match *self {
            Color::White => Rank::Seventh,
            Color::Black => Rank::Second,
        }
    }
}

impl Not for Color {
    type Output = Color;

    /// Get the other color.
    #[inline]
    fn not(self) -> Color {
        if self == Color::White {
            Color::Black
        } else {
            Color::White
        }
    }
}
<commit_msg>Document `Color::to_fourth_rank` and fix doc typos<commit_after>use crate::rank::Rank;
use std::ops::Not;

/// Represent a color.
#[derive(PartialOrd, PartialEq, Eq, Copy, Clone, Debug, Hash)]
pub enum Color {
    White,
    Black,
}

/// How many colors are there?
pub const NUM_COLORS: usize = 2;
/// List all colors
pub const ALL_COLORS: [Color; NUM_COLORS] = [Color::White, Color::Black];

impl Color {
    /// Convert the `Color` to a `usize` for table lookups.
    #[inline]
    pub fn to_index(&self) -> usize {
        *self as usize
    }

    /// Convert a `Color` to my backrank, which represents the starting rank
    /// for my pieces.
    #[inline]
    pub fn to_my_backrank(&self) -> Rank {
        match *self {
            Color::White => Rank::First,
            Color::Black => Rank::Eighth,
        }
    }

    /// Convert a `Color` to my opponents backrank, which represents the starting rank for the
    /// opponents pieces.
    #[inline]
    pub fn to_their_backrank(&self) -> Rank {
        match *self {
            Color::White => Rank::Eighth,
            Color::Black => Rank::First,
        }
    }

    /// Convert a `Color` to my second rank, which represents the starting rank for my pawns.
    #[inline]
    pub fn to_second_rank(&self) -> Rank {
        match *self {
            Color::White => Rank::Second,
            Color::Black => Rank::Seventh,
        }
    }

    /// Convert a `Color` to my fourth rank, which represents the rank of my pawns when
    /// moving two squares forward.
    #[inline]
    pub fn to_fourth_rank(&self) -> Rank {
        match *self {
            Color::White => Rank::Fourth,
            Color::Black => Rank::Fifth,
        }
    }

    /// Convert a `Color` to my seventh rank, which represents the rank before pawn promotion.
    #[inline]
    pub fn to_seventh_rank(&self) -> Rank {
        match *self {
            Color::White => Rank::Seventh,
            Color::Black => Rank::Second,
        }
    }
}

impl Not for Color {
    type Output = Color;

    /// Get the other color.
    #[inline]
    fn not(self) -> Color {
        if self == Color::White {
            Color::Black
        } else {
            Color::White
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Handlers and types for agent's actions.
//!
//! The basic functionality that a GRR agent exposes is called an _action_.
//! Actions are invoked by the server (when running a _flow_), should gather
//! requested information and report back to the server.
//!
//! In RRG each action consists of three components: a request type, a response
//! type and an action handler. Request and response types wrap lower-level
//! Protocol Buffer messages sent by and to the GRR server. Handlers accept one
//! instance of the corresponding request type and send some (zero or more)
//! instances of the corresponding response type.

#[cfg(target_os = "linux")]
pub mod filesystems;

#[cfg(target_family = "unix")]
pub mod interfaces;

#[cfg(feature = "action-metadata")]
pub mod metadata;

pub mod startup;

#[cfg(feature = "action-listdir")]
pub mod listdir;

pub mod timeline;
pub mod network;

#[cfg(feature = "action-stat")]
pub mod stat;

pub mod insttime;
pub mod memsize;
pub mod finder;

use crate::session::{self, Session, Task};

/// Abstraction for action-specific requests.
///
/// Protocol Buffer messages received from the GRR server are not necessarily
/// easy to work with and are hardly idiomatic to Rust. For this reason, actions
/// should define more structured data types to represent their input and should
/// be able to parse raw messages into them.
pub trait Request: Sized {

    /// A type of the corresponding raw proto message.
    type Proto: protobuf::Message + Default;

    /// A method for converting raw proto messages into structured requests.
    fn from_proto(proto: Self::Proto) -> Result<Self, session::ParseError>;
}

/// Abstraction for action-specific responses.
///
/// Like with the [`Request`] type, Protocol Buffer messages sent to the GRR
/// server are very idiomatic to Rust. For this reason, actions should define
/// more structured data types to represent responses and provide a way to
/// convert them into the wire format.
///
/// Note that because of the design flaws in the protocol, actions also need to
/// specify a name of the wrapper RDF class from the Python implementation.
/// Hopefully, one day this issue would be fixed and class names will not leak
/// into the specification.
///
/// [`Request`]: trait.Request.html
pub trait Response: Sized {

    /// A name of the corresponding RDF class.
    const RDF_NAME: Option<&'static str>;

    /// A type of the corresponding raw proto message.
    type Proto: protobuf::Message + Default;

    /// A method for converting structured responses into raw proto messages.
    fn into_proto(self) -> Self::Proto;
}

impl Request for () {

    type Proto = protobuf::well_known_types::Empty;

    fn from_proto(_: protobuf::well_known_types::Empty) -> Result<(), session::ParseError> {
        Ok(())
    }
}

impl Response for () {

    const RDF_NAME: Option<&'static str> = None;

    type Proto = protobuf::well_known_types::Empty;

    fn into_proto(self) -> protobuf::well_known_types::Empty {
        protobuf::well_known_types::Empty::new()
    }
}

/// Dispatches `task` to a handler appropriate for the given `action`.
///
/// This method is a mapping between action names (as specified in the protocol)
/// and action handlers (implemented on the agent).
///
/// If the given action is unknown (or not yet implemented), this function will
/// return an error.
pub fn dispatch<'s, S>(action: &str, task: Task<'s, S>) -> session::Result<()>
where
    S: Session,
{
    match action {
        "SendStartupInfo" => task.execute(self::startup::handle),

        #[cfg(feature = "action-metadata")]
        "GetClientInfo" => task.execute(self::metadata::handle),

        #[cfg(feature = "action-listdir")]
        "ListDirectory" => task.execute(self::listdir::handle),

        "Timeline" => task.execute(self::timeline::handle),
        "ListNetworkConnections" => task.execute(self::network::handle),

        #[cfg(feature = "action-stat")]
        "GetFileStat" => task.execute(self::stat::handle),

        "GetInstallDate" => task.execute(self::insttime::handle),

        #[cfg(target_family = "unix")]
        "EnumerateInterfaces" => task.execute(self::interfaces::handle),

        #[cfg(target_os = "linux")]
        "EnumerateFilesystems" => task.execute(self::filesystems::handle),

        "GetMemorySize" => task.execute(self::memsize::handle),
        action => return Err(session::Error::Dispatch(String::from(action))),
    }
}
<commit_msg>Add a TODO comment about the `startup` action.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Handlers and types for agent's actions.
//!
//! The basic functionality that a GRR agent exposes is called an _action_.
//! Actions are invoked by the server (when running a _flow_), should gather
//! requested information and report back to the server.
//!
//! In RRG each action consists of three components: a request type, a response
//! type and an action handler. Request and response types wrap lower-level
//! Protocol Buffer messages sent by and to the GRR server. Handlers accept one
//! instance of the corresponding request type and send some (zero or more)
//! instances of the corresponding response type.

#[cfg(target_os = "linux")]
pub mod filesystems;

#[cfg(target_family = "unix")]
pub mod interfaces;

#[cfg(feature = "action-metadata")]
pub mod metadata;

#[cfg(feature = "action-listdir")]
pub mod listdir;

pub mod timeline;
pub mod network;

#[cfg(feature = "action-stat")]
pub mod stat;

pub mod insttime;
pub mod memsize;
pub mod finder;

// TODO: `startup` should not be an action but just a message sent when the
// agent boots up.
pub mod startup;

use crate::session::{self, Session, Task};

/// Abstraction for action-specific requests.
///
/// Protocol Buffer messages received from the GRR server are not necessarily
/// easy to work with and are hardly idiomatic to Rust. For this reason, actions
/// should define more structured data types to represent their input and should
/// be able to parse raw messages into them.
pub trait Request: Sized {

    /// A type of the corresponding raw proto message.
    type Proto: protobuf::Message + Default;

    /// A method for converting raw proto messages into structured requests.
    fn from_proto(proto: Self::Proto) -> Result<Self, session::ParseError>;
}

/// Abstraction for action-specific responses.
///
/// Like with the [`Request`] type, Protocol Buffer messages sent to the GRR
/// server are very idiomatic to Rust. For this reason, actions should define
/// more structured data types to represent responses and provide a way to
/// convert them into the wire format.
///
/// Note that because of the design flaws in the protocol, actions also need to
/// specify a name of the wrapper RDF class from the Python implementation.
/// Hopefully, one day this issue would be fixed and class names will not leak
/// into the specification.
///
/// [`Request`]: trait.Request.html
pub trait Response: Sized {

    /// A name of the corresponding RDF class.
    const RDF_NAME: Option<&'static str>;

    /// A type of the corresponding raw proto message.
    type Proto: protobuf::Message + Default;

    /// A method for converting structured responses into raw proto messages.
    fn into_proto(self) -> Self::Proto;
}

impl Request for () {

    type Proto = protobuf::well_known_types::Empty;

    fn from_proto(_: protobuf::well_known_types::Empty) -> Result<(), session::ParseError> {
        Ok(())
    }
}

impl Response for () {

    const RDF_NAME: Option<&'static str> = None;

    type Proto = protobuf::well_known_types::Empty;

    fn into_proto(self) -> protobuf::well_known_types::Empty {
        protobuf::well_known_types::Empty::new()
    }
}

/// Dispatches `task` to a handler appropriate for the given `action`.
///
/// This method is a mapping between action names (as specified in the protocol)
/// and action handlers (implemented on the agent).
///
/// If the given action is unknown (or not yet implemented), this function will
/// return an error.
pub fn dispatch<'s, S>(action: &str, task: Task<'s, S>) -> session::Result<()>
where
    S: Session,
{
    match action {
        "SendStartupInfo" => task.execute(self::startup::handle),

        #[cfg(feature = "action-metadata")]
        "GetClientInfo" => task.execute(self::metadata::handle),

        #[cfg(feature = "action-listdir")]
        "ListDirectory" => task.execute(self::listdir::handle),

        "Timeline" => task.execute(self::timeline::handle),
        "ListNetworkConnections" => task.execute(self::network::handle),

        #[cfg(feature = "action-stat")]
        "GetFileStat" => task.execute(self::stat::handle),

        "GetInstallDate" => task.execute(self::insttime::handle),

        #[cfg(target_family = "unix")]
        "EnumerateInterfaces" => task.execute(self::interfaces::handle),

        #[cfg(target_os = "linux")]
        "EnumerateFilesystems" => task.execute(self::filesystems::handle),

        "GetMemorySize" => task.execute(self::memsize::handle),
        action => return Err(session::Error::Dispatch(String::from(action))),
    }
}
<|endoftext|>


<commit_before>//! Syscall's stream aggregators used to ingest the flow of syscall events from the collector
//! to messaging systems.

use kafka::producer::{Producer, Record, RequiredAcks};
use std::time::Duration;
use std::marker::Sized;
use kafka;

pub trait Aggregator<E, C> {
    fn boot(config: C) -> Result<Self, E> where Self: Sized;

    fn do_aggregate(&mut self, body: String);
}

pub struct KafkaAggregator {
    producer: Producer,
    topic: &'static str
}

pub struct KafkaConfig {
    pub hosts: Vec<String>,
    pub ack_timeout: Duration,
    pub topic: &'static str
}

/// Implementation of the syscall's aggregator which emits the stream of syscall events
/// to Kafka brokers.
impl Aggregator<kafka::Error, KafkaConfig> for KafkaAggregator {

    fn boot(config: KafkaConfig) -> Result<KafkaAggregator, kafka::Error> {
        let producer = match Producer::from_hosts(config.hosts)
                .with_ack_timeout(config.ack_timeout)
                .create() {
                Ok(p) => p,
                Err(e) => return Err(e)
        };
        Ok(KafkaAggregator {
            topic: config.topic,
            producer: producer
        })
    }

    fn do_aggregate(&mut self, body: String) {
        self.producer.send(&Record::from_value(self.topic, body.as_bytes())).unwrap();
    }
}<commit_msg>refactored<commit_after>//! Syscall's stream aggregators used to ingest the flow of syscall events from the collector
//! to messaging systems.
use std::time::Duration;
use kafka::producer::{Producer, Record, RequiredAcks};
use kafka;
use config::KafkaConfig;

pub trait Aggregator<T> {

    fn do_aggregate(&mut self, body: T);
}

pub struct KafkaAggregator {
    /// an instance of the Kafka producer
    producer: Option<Producer>,
    /// kafka configuration
    config: KafkaConfig
}

/// Implementation of the syscall's aggregator which emits the stream of syscall events
/// to Kafka brokers.
impl Aggregator<String> for KafkaAggregator {

    fn do_aggregate(&mut self, body: String) {
        match self.producer {
            Some(ref mut p) => {
                p.send(&Record::from_value(&self.config.topic, body.as_bytes())).unwrap();
            }
            None => {}
        }
    }
}

impl KafkaAggregator {

    pub fn new(config: KafkaConfig) -> KafkaAggregator {
        KafkaAggregator {
            producer: None,
            config: config
        }
    }

    pub fn start(&mut self) -> Result<(), kafka::Error> {
        self.producer = match Producer::from_hosts(self.config.hosts.clone())
                .with_ack_timeout(Duration::from_secs(self.config.ack_timeout))
                .create() {
                    Ok(p) => Some(p),
                    Err(e) => return Err(e)
        };
        Ok(())
    }
}<|endoftext|>