<commit_before>use ruma_identifiers::RoomVersionId;

use crate::{Error, Result};

#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum RoomDisposition {
    /// A room version that has a stable specification.
    Stable,
    /// A room version that is not yet fully specified.
    Unstable,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum EventFormatVersion {
    /// $id:server event id format
    V1,
    /// MSC1659-style $hash event id format: introduced for room v3
    V2,
    /// MSC1884-style $hash format: introduced for room v4
    V3,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum StateResolutionVersion {
    /// State resolution for rooms at version 1.
    V1,
    /// State resolution for room at version 2 or later.
    V2,
}

#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomVersion {
    /// The version this room is set to.
    pub version: RoomVersionId,
    /// The stability of this room.
    pub disposition: RoomDisposition,
    /// The format of the EventId.
    pub event_format: EventFormatVersion,
    /// Which state resolution algorithm is used.
    pub state_res: StateResolutionVersion,
    // FIXME: not sure what this one means?
    pub enforce_key_validity: bool,

    /// `m.room.aliases` had special auth rules and redaction rules
    /// before room version 6.
    ///
    /// before MSC2261/MSC2432,
    pub special_case_aliases_auth: bool,
    /// Strictly enforce canonical json, do not allow:
    /// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1]
    /// * Floats
    /// * NaN, Infinity, -Infinity
    pub strict_canonicaljson: bool,
    /// Verify notifications key while checking m.room.power_levels.
    ///
    /// bool: MSC2209: Check 'notifications'
    pub limit_notifications_power_levels: bool,
    /// Extra rules when verifying redaction events.
    pub extra_redaction_checks: bool,
    /// Allow knocking in event authentication.
    ///
    /// See: https://spec.matrix.org/unstable/rooms/v7/ for more information.
    pub allow_knocking: bool,
    /// Adds support for the restricted join rule.
    ///
    /// See: https://github.com/matrix-org/matrix-doc/pull/3289 for more information.
    pub restricted_join_rules: bool,
}

impl RoomVersion {
    pub const VERSION1: Self = Self {
        version: RoomVersionId::V1,
        disposition: RoomDisposition::Stable,
        event_format: EventFormatVersion::V1,
        state_res: StateResolutionVersion::V1,
        enforce_key_validity: false,
        special_case_aliases_auth: true,
        strict_canonicaljson: false,
        limit_notifications_power_levels: false,
        extra_redaction_checks: false,
        allow_knocking: false,
        restricted_join_rules: false,
    };

    pub const VERSION2: Self = Self {
        version: RoomVersionId::V2,
        state_res: StateResolutionVersion::V2,
        ..Self::VERSION1
    };

    pub const VERSION3: Self = Self {
        version: RoomVersionId::V3,
        event_format: EventFormatVersion::V2,
        extra_redaction_checks: true,
        ..Self::VERSION2
    };

    pub const VERSION4: Self =
        Self { version: RoomVersionId::V4, event_format: EventFormatVersion::V3, ..Self::VERSION3 };

    pub const VERSION5: Self =
        Self { version: RoomVersionId::V5, enforce_key_validity: true, ..Self::VERSION4 };

    pub const VERSION6: Self = Self {
        version: RoomVersionId::V5,
        special_case_aliases_auth: false,
        strict_canonicaljson: true,
        limit_notifications_power_levels: true,
        ..Self::VERSION5
    };

    #[cfg(feature = "unstable-pre-spec")]
    pub const VERSION7: Self = Self {
        version: RoomVersionId::V7,
        // FIXME: once room version 7 is stabilized move this to version 8
        disposition: RoomDisposition::Unstable,
        allow_knocking: true,
        ..Self::VERSION6
    };

    #[cfg(feature = "unstable-pre-spec")]
    pub const VERSION8: Self =
        Self { version: RoomVersionId::V8, restricted_join_rules: true, ..Self::VERSION7 };

    #[cfg(feature = "unstable-pre-spec")]
    pub const VERSION9: Self = Self { version: RoomVersionId::V9, ..Self::VERSION8 };

    pub fn new(version: &RoomVersionId) -> Result<Self> {
        Ok(match version {
            RoomVersionId::V1 => Self::VERSION1,
            RoomVersionId::V2 => Self::VERSION2,
            RoomVersionId::V3 => Self::VERSION3,
            RoomVersionId::V4 => Self::VERSION4,
            RoomVersionId::V5 => Self::VERSION5,
            RoomVersionId::V6 => Self::VERSION6,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V7 => Self::VERSION7,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V8 => Self::VERSION8,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V9 => Self::VERSION9,
            ver => return Err(Error::Unsupported(format!("found version `{}`", ver.as_str()))),
        })
    }
}
<commit_msg>state-res: Remove unused RoomVersion::version field<commit_after>use ruma_identifiers::RoomVersionId;

use crate::{Error, Result};

#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum RoomDisposition {
    /// A room version that has a stable specification.
    Stable,
    /// A room version that is not yet fully specified.
    Unstable,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum EventFormatVersion {
    /// $id:server event id format
    V1,
    /// MSC1659-style $hash event id format: introduced for room v3
    V2,
    /// MSC1884-style $hash format: introduced for room v4
    V3,
}

#[derive(Debug)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum StateResolutionVersion {
    /// State resolution for rooms at version 1.
    V1,
    /// State resolution for room at version 2 or later.
    V2,
}

#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct RoomVersion {
    /// The stability of this room.
    pub disposition: RoomDisposition,
    /// The format of the EventId.
    pub event_format: EventFormatVersion,
    /// Which state resolution algorithm is used.
    pub state_res: StateResolutionVersion,
    // FIXME: not sure what this one means?
    pub enforce_key_validity: bool,

    /// `m.room.aliases` had special auth rules and redaction rules
    /// before room version 6.
    ///
    /// before MSC2261/MSC2432,
    pub special_case_aliases_auth: bool,
    /// Strictly enforce canonical json, do not allow:
    /// * Integers outside the range of [-2 ^ 53 + 1, 2 ^ 53 - 1]
    /// * Floats
    /// * NaN, Infinity, -Infinity
    pub strict_canonicaljson: bool,
    /// Verify notifications key while checking m.room.power_levels.
    ///
    /// bool: MSC2209: Check 'notifications'
    pub limit_notifications_power_levels: bool,
    /// Extra rules when verifying redaction events.
    pub extra_redaction_checks: bool,
    /// Allow knocking in event authentication.
    ///
    /// See: https://spec.matrix.org/unstable/rooms/v7/ for more information.
    pub allow_knocking: bool,
    /// Adds support for the restricted join rule.
    ///
    /// See: https://github.com/matrix-org/matrix-doc/pull/3289 for more information.
    pub restricted_join_rules: bool,
}

impl RoomVersion {
    pub const VERSION1: Self = Self {
        disposition: RoomDisposition::Stable,
        event_format: EventFormatVersion::V1,
        state_res: StateResolutionVersion::V1,
        enforce_key_validity: false,
        special_case_aliases_auth: true,
        strict_canonicaljson: false,
        limit_notifications_power_levels: false,
        extra_redaction_checks: false,
        allow_knocking: false,
        restricted_join_rules: false,
    };

    pub const VERSION2: Self = Self { state_res: StateResolutionVersion::V2, ..Self::VERSION1 };

    pub const VERSION3: Self = Self {
        event_format: EventFormatVersion::V2,
        extra_redaction_checks: true,
        ..Self::VERSION2
    };

    pub const VERSION4: Self = Self { event_format: EventFormatVersion::V3, ..Self::VERSION3 };

    pub const VERSION5: Self = Self { enforce_key_validity: true, ..Self::VERSION4 };

    pub const VERSION6: Self = Self {
        special_case_aliases_auth: false,
        strict_canonicaljson: true,
        limit_notifications_power_levels: true,
        ..Self::VERSION5
    };

    #[cfg(feature = "unstable-pre-spec")]
    pub const VERSION7: Self = Self {
        // FIXME: once room version 7 is stabilized move this to version 8
        disposition: RoomDisposition::Unstable,
        allow_knocking: true,
        ..Self::VERSION6
    };

    #[cfg(feature = "unstable-pre-spec")]
    pub const VERSION8: Self = Self { restricted_join_rules: true, ..Self::VERSION7 };

    #[cfg(feature = "unstable-pre-spec")]
    pub const VERSION9: Self = Self::VERSION8;

    pub fn new(version: &RoomVersionId) -> Result<Self> {
        Ok(match version {
            RoomVersionId::V1 => Self::VERSION1,
            RoomVersionId::V2 => Self::VERSION2,
            RoomVersionId::V3 => Self::VERSION3,
            RoomVersionId::V4 => Self::VERSION4,
            RoomVersionId::V5 => Self::VERSION5,
            RoomVersionId::V6 => Self::VERSION6,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V7 => Self::VERSION7,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V8 => Self::VERSION8,
            #[cfg(feature = "unstable-pre-spec")]
            RoomVersionId::V9 => Self::VERSION9,
            ver => return Err(Error::Unsupported(format!("found version `{}`", ver.as_str()))),
        })
    }
}
<|endoftext|>


<commit_before>//! Experimental triangulation algorithm.

use graphics::modular_index::{offset, previous, next};

// Local crate.
use Vector2d = vector2d::Vector2d;

static EPSILON: f64 = 0.0000000001;

/// Compute area of contour.
pub fn area(contour: &[Vector2d]) -> f64 {
    let n = contour.len();
    let mut sum = 0.0_f64;

    for i in range(0, n) {
        let q = i;
        let p = previous(n, i);
        sum += contour.get(p).unwrap().get_x()
            * contour.get(q).unwrap().get_y()
            - contour.get(q).unwrap().get_x()
            * contour.get(p).unwrap().get_y();
    }

    sum * 0.5_f64
}

/// InsideTriangle decides if a point P is Inside of the triangle
/// defined by A, B, C.
pub fn inside_triangle(
    a_x: f64, a_y: f64,
    b_x: f64, b_y: f64,
    c_x: f64, c_y: f64,
    p_x: f64, p_y: f64
) -> bool {

    let (bcx, bcy) = (c_x - b_x, c_y - b_y);
    let (cax, cay) = (a_x - c_x, a_y - c_y);
    let (abx, aby) = (b_x - a_x, b_y - a_y);
    let (apx, apy) = (p_x - a_x, p_y - a_y);
    let (bpx, bpy) = (p_x - b_x, p_y - b_y);
    let (cpx, cpy) = (p_x - c_x, p_y - c_y);

    let bc_cross_bp = bcx * bpy - bcy * bpx;
    let ab_cross_ap = abx * apy - aby * apx;
    let ca_cross_cp = cax * cpy - cay * cpx;

    bc_cross_bp >= 0.0_f64
    && ca_cross_cp >= 0.0_f64
    && ab_cross_ap >= 0.0_f64
}

/// Check for self intersection.
pub fn snip(
    contour: &[Vector2d],
    triangle: [uint, ..3],
    n: uint,
    vertex_indices: &Vec<uint>
) -> bool {
    let (u, v, w) = (triangle[0], triangle[1], triangle[2]);

    let a_pos = contour.get(*vertex_indices.get(u)).unwrap();
    let b_pos = contour.get(*vertex_indices.get(v)).unwrap();
    let c_pos = contour.get(*vertex_indices.get(w)).unwrap();

    let (ax, ay) = (a_pos.get_x(), a_pos.get_y());
    let (bx, by) = (b_pos.get_x(), b_pos.get_y());
    let (cx, cy) = (c_pos.get_x(), c_pos.get_y());

    if EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) {
        return false;
    }

    for p in range(0, n) {
        // Do not check for any of the vertices in the triangle.
        if (p == u) || (p == v) || (p == w) { continue; }

        let p_pos = contour.get(*vertex_indices.get(p)).unwrap();
        if inside_triangle(
                ax, ay,
                bx, by,
                cx, cy,
                p_pos.get_x(), p_pos.get_y()
        ) {
            return false;
        }
    }

    true
}

/// Triangulize a polygon contour.
pub fn process(
    contour: &[Vector2d]
) -> Option<Vec<Vector2d>> {
    /* allocate and initialize list of Vertices in polygon */

    let n = contour.len();
    if n < 3 { return None; }

    let mut result: Vec<Vector2d> = Vec::new();
    let mut vertex_indices: Vec<uint> = Vec::with_capacity(n);

    /* we want a counter-clockwise polygon in V */

    // Computes the area which has opposite signs
    // whether the polygon is clock-wise or counter-clockwise.
    if 0.0_f64 < area(contour) {
        for v in range(0, n) { vertex_indices.push(v); }
    } else {
        // Add indices in reverse order.
        for v in range(0, n) { vertex_indices.push((n-1)-v); }
    }

    // Stores the number of vertices.
    // Used instead of `vertex_indices.len()` to emulate removing of vertices.
    let mut number_of_vertices = n;

    /*  remove nv-2 Vertices, creating 1 triangle every time */

    // Used for error detection.
    let mut count = 2 * number_of_vertices;

    let mut v = number_of_vertices - 1;
    while number_of_vertices > 2 {
        /* if we loop, it is probably a non-simple polygon */
        if count <= 0 {
            //** Triangulate: ERROR - probable bad polygon!
            return None;
        }

        count -= 1;

        /* three consecutive vertices in current polygon, <u,v,w> */
        let triangle = [
            v,
            next(number_of_vertices, v),
            offset(number_of_vertices, v, 2)
        ];
        v = triangle[1];

        if snip(contour, triangle, number_of_vertices, &mut vertex_indices) {
            for &i in triangle.iter() {
                result.push(*contour.get(*vertex_indices.get(i)).unwrap());
            }

            /* remove v from remaining polygon */
            for i in range(0, number_of_vertices - 3) {
                let s = v + i;
                let t = v + i + 1;

                *vertex_indices.get_mut(s) = *vertex_indices.get(t);
            }

            // "Removed" a vertex.
            number_of_vertices -= 1;

            /* resest error detection counter */
            count = 2 * number_of_vertices;
        }
    }

    Some(result)
}

<commit_msg>Update to latest Rust<commit_after>//! Experimental triangulation algorithm.

use graphics::modular_index::{offset, previous, next};

// Local crate.
use Vector2d = vector2d::Vector2d;

static EPSILON: f64 = 0.0000000001;

/// Compute area of contour.
pub fn area(contour: &[Vector2d]) -> f64 {
    let n = contour.len();
    let mut sum = 0.0_f64;

    for i in range(0, n) {
        let q = i;
        let p = previous(n, i);
        sum += contour.get(p).unwrap().get_x()
            * contour.get(q).unwrap().get_y()
            - contour.get(q).unwrap().get_x()
            * contour.get(p).unwrap().get_y();
    }

    sum * 0.5_f64
}

/// InsideTriangle decides if a point P is Inside of the triangle
/// defined by A, B, C.
pub fn inside_triangle(
    a_x: f64, a_y: f64,
    b_x: f64, b_y: f64,
    c_x: f64, c_y: f64,
    p_x: f64, p_y: f64
) -> bool {

    let (bcx, bcy) = (c_x - b_x, c_y - b_y);
    let (cax, cay) = (a_x - c_x, a_y - c_y);
    let (abx, aby) = (b_x - a_x, b_y - a_y);
    let (apx, apy) = (p_x - a_x, p_y - a_y);
    let (bpx, bpy) = (p_x - b_x, p_y - b_y);
    let (cpx, cpy) = (p_x - c_x, p_y - c_y);

    let bc_cross_bp = bcx * bpy - bcy * bpx;
    let ab_cross_ap = abx * apy - aby * apx;
    let ca_cross_cp = cax * cpy - cay * cpx;

    bc_cross_bp >= 0.0_f64
    && ca_cross_cp >= 0.0_f64
    && ab_cross_ap >= 0.0_f64
}

/// Check for self intersection.
pub fn snip(
    contour: &[Vector2d],
    triangle: [uint, ..3],
    n: uint,
    vertex_indices: &Vec<uint>
) -> bool {
    let (u, v, w) = (triangle[0], triangle[1], triangle[2]);

    let a_pos = contour.get(vertex_indices[u]).unwrap();
    let b_pos = contour.get(vertex_indices[v]).unwrap();
    let c_pos = contour.get(vertex_indices[w]).unwrap();

    let (ax, ay) = (a_pos.get_x(), a_pos.get_y());
    let (bx, by) = (b_pos.get_x(), b_pos.get_y());
    let (cx, cy) = (c_pos.get_x(), c_pos.get_y());

    if EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) {
        return false;
    }

    for p in range(0, n) {
        // Do not check for any of the vertices in the triangle.
        if (p == u) || (p == v) || (p == w) { continue; }

        let p_pos = contour.get(vertex_indices[p]).unwrap();
        if inside_triangle(
                ax, ay,
                bx, by,
                cx, cy,
                p_pos.get_x(), p_pos.get_y()
        ) {
            return false;
        }
    }

    true
}

/// Triangulize a polygon contour.
pub fn process(
    contour: &[Vector2d]
) -> Option<Vec<Vector2d>> {
    /* allocate and initialize list of Vertices in polygon */

    let n = contour.len();
    if n < 3 { return None; }

    let mut result: Vec<Vector2d> = Vec::new();
    let mut vertex_indices: Vec<uint> = Vec::with_capacity(n);

    /* we want a counter-clockwise polygon in V */

    // Computes the area which has opposite signs
    // whether the polygon is clock-wise or counter-clockwise.
    if 0.0_f64 < area(contour) {
        for v in range(0, n) { vertex_indices.push(v); }
    } else {
        // Add indices in reverse order.
        for v in range(0, n) { vertex_indices.push((n-1)-v); }
    }

    // Stores the number of vertices.
    // Used instead of `vertex_indices.len()` to emulate removing of vertices.
    let mut number_of_vertices = n;

    /*  remove nv-2 Vertices, creating 1 triangle every time */

    // Used for error detection.
    let mut count = 2 * number_of_vertices;

    let mut v = number_of_vertices - 1;
    while number_of_vertices > 2 {
        /* if we loop, it is probably a non-simple polygon */
        if count <= 0 {
            //** Triangulate: ERROR - probable bad polygon!
            return None;
        }

        count -= 1;

        /* three consecutive vertices in current polygon, <u,v,w> */
        let triangle = [
            v,
            next(number_of_vertices, v),
            offset(number_of_vertices, v, 2)
        ];
        v = triangle[1];

        if snip(contour, triangle, number_of_vertices, &mut vertex_indices) {
            for &i in triangle.iter() {
                result.push(*contour.get(vertex_indices[i]).unwrap());
            }

            /* remove v from remaining polygon */
            for i in range(0, number_of_vertices - 3) {
                let s = v + i;
                let t = v + i + 1;

                *vertex_indices.get_mut(s) = vertex_indices[t];
            }

            // "Removed" a vertex.
            number_of_vertices -= 1;

            /* resest error detection counter */
            count = 2 * number_of_vertices;
        }
    }

    Some(result)
}

<|endoftext|>


<commit_before>//! This example will showcase one way on how to extend Serentiy with a
//! time-scheduler and an event-trigger-system.
//! We will create a remind-me command that will send a message after a
//! a demanded amount of time. Once the message has been sent, the user can
//! react to it, triggering an event to send another message.
use std::{collections::HashSet, env, hash::{Hash, Hasher},
    sync::Arc,
};
use serenity::{
    prelude::*,
    framework::standard::{
        Args, CommandResult, CommandGroup,
        DispatchError, HelpOptions, help_commands, StandardFramework,
        macros::{command, group, help},
    },
    http::Http,
    model::prelude::*,
};
// We will use this crate as event dispatcher.
use hey_listen::sync::{ParallelDispatcher as Dispatcher,
    ParallelDispatcherRequest as DispatcherRequest};
// And this crate to schedule our tasks.
use white_rabbit::{Utc, Scheduler, DateResult, Duration};

// This enum represents possible events a listener might wait for.
// In this case, we want to dispatch an event when a reaction is added.
// Serenity's event-enum is not suitable for this.
// First it offers too many variants we do not need, but most importantly,
// it lacks the `Default`-trait which makes sense
// as the enum-fields have no clear logical default value. But without it,
// constructing mock-variants becomes difficult.
//
// As a result, we make our own slick event-enum!
#[derive(Clone)]
enum DispatchEvent {
    ReactEvent(MessageId, UserId),
}

// We need to implement equality for our enum.
// One could test variants only. In this case, we want to know who reacted
// on which message.
impl PartialEq for DispatchEvent {
    fn eq(&self, other: &DispatchEvent) -> bool {
        match (self, other) {
            (DispatchEvent::ReactEvent(self_message_id, self_user_id),
            DispatchEvent::ReactEvent(other_message_id, other_user_id)) => {
                self_message_id == other_message_id &&
                self_user_id == other_user_id
            }
        }
    }
}

impl Eq for DispatchEvent {}

// See following Clippy-lint:
// https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
impl Hash for DispatchEvent {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            DispatchEvent::ReactEvent(msg_id, user_id) => {
                msg_id.hash(state);
                user_id.hash(state);
            }
        }
    }
}

struct DispatcherKey;
impl TypeMapKey for DispatcherKey {
    type Value = Arc<RwLock<Dispatcher<DispatchEvent>>>;
}

struct SchedulerKey;
impl TypeMapKey for SchedulerKey {
    type Value = Arc<RwLock<Scheduler>>;
}

struct Handler;
impl EventHandler for Handler {
    // We want to dispatch an event whenever a new reaction has been added.
    fn reaction_add(&self, context: Context, reaction: Reaction) {
        let dispatcher = {
            let mut context = context.data.write();
            context.get_mut::<DispatcherKey>().expect("Expected Dispatcher.").clone()
        };

        dispatcher.write().dispatch_event(
            &DispatchEvent::ReactEvent(reaction.message_id, reaction.user_id));
    }
}

group!({
    name: "remind_me",
    options: {
        prefixes: ["rm", "reminder"],
    },
    commands: [set_reminder],
});

#[help]
fn my_help(
    context: &mut Context,
    msg: &Message,
    args: Args,
    help_options: &'static HelpOptions,
    groups: &[&'static CommandGroup],
    owners: HashSet<UserId>
) -> CommandResult {
    help_commands::with_embeds(context, msg, args, &help_options, groups, owners)
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect(
        "Expected a token in the environment",
    );
    let mut client = Client::new(&token, Handler)
        .expect("Err creating client");

    {
        let mut data = client.data.write();
        // We create a new scheduler with 4 internal threads. Why 4? It really
        // is just an arbitrary number, you are often better setting this
        // based on your CPU.
        // When a task is due, a thread from the threadpool will be used to
        // avoid blocking the scheduler thread.
        let scheduler = Scheduler::new(4);
        let scheduler = Arc::new(RwLock::new(scheduler));

        let mut dispatcher: Dispatcher<DispatchEvent> = Dispatcher::default();
        // Once receiving an event to dispatch, the amount of threads
        // set via `num_threads` will dispatch in parallel.
        dispatcher.num_threads(4).expect("Could not construct threadpool");

        data.insert::<DispatcherKey>(Arc::new(RwLock::new(dispatcher)));
        data.insert::<SchedulerKey>(scheduler);
    }

    // We will fetch your bot's id.
    let bot_id = match client.cache_and_http.http.get_current_application_info() {
        Ok(info) => {
            info.id
        },
        Err(why) => panic!("Could not access application info: {:?}", why),
    };

    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        StandardFramework::new()
        .configure(|c| c
            .with_whitespace(true)
            .on_mention(Some(bot_id))
            .prefix("~")
            .delimiters(vec![", ", ","]))
        .on_dispatch_error(|ctx, msg, error| {
            if let DispatchError::Ratelimited(seconds) = error {
                let _ = msg.channel_id.say(&ctx.http, &format!("Try this again in {} seconds.", seconds));
            }
        })
        .after(|_ctx, _msg, cmd_name, error| {

        if let Err(why) = error {
            println!("Error in {}: {:?}", cmd_name, why);
        }
    })
        .help(&MY_HELP)
        .group(&REMIND_ME_GROUP)
    );

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

// Just a helper-function for creating the closure we want to use as listener.
// It saves us from writing the same trigger twice for repeated and non-repeated
// tasks (see remind-me command below).
fn thanks_for_reacting(http: Arc<Http>, channel: ChannelId) ->
    Box<Fn(&DispatchEvent) -> Option<DispatcherRequest> + Send + Sync> {

    Box::new(move |_| {
        if let Err(why) = channel.say(&http, "Thanks for reacting!") {
            println!("Could not send message: {:?}", why);
        }

        Some(DispatcherRequest::StopListening)
    })
}

#[command]
#[aliases("add")]
fn set_reminder(context: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
    // It might be smart to set a moderately high minimum value for `time`
    // to avoid abuse like tasks that repeat every 100ms, especially since
    // channels have send-message rate limits.
    let time: u64 = args.single()?;
    let repeat: bool = args.single()?;
    let args = args.rest().to_string();

    let scheduler = {
        let mut context = context.data.write();
        context.get_mut::<SchedulerKey>().expect("Expected Scheduler.").clone()
    };

    let dispatcher = {
        let mut context = context.data.write();
        context.get_mut::<DispatcherKey>().expect("Expected Dispatcher.").clone()
    };

    let http = context.http.clone();
    let msg = msg.clone();

    let mut scheduler = scheduler.write();

    // First, we check if the user wants a repeated task or not.
    if repeat {
        // Chrono's duration can also be negative
        // and therefore we cast to `i64`.
        scheduler.add_task_duration(Duration::milliseconds(time as i64), move |_| {
            let bot_msg = match msg.channel_id.say(&http, &args) {
                Ok(msg) => msg,
                // We could not send the message, thus we will try sending it
                // again in five seconds.
                // It might be wise to keep a counter for maximum tries.
                // If the channel got deleted, trying to send a message will
                // always fail.
                Err(why) => {
                    println!("Error sending message: {:?}.", why);

                    return DateResult::Repeat(
                        Utc::now() + Duration::milliseconds(5000))
                },
            };

            let http = http.clone();

            // We add a function to dispatch for a certain event.
            dispatcher.write()
                .add_fn(DispatchEvent::ReactEvent(bot_msg.id, msg.author.id),
                    // The `thanks_for_reacting`-function creates a function
                    // to schedule.
                    thanks_for_reacting(http, bot_msg.channel_id));

            // We return that our date shall happen again, therefore we need
            // to tell when this shall be.
            DateResult::Repeat(Utc::now() + Duration::milliseconds(time as i64))
        });
    } else {
        // Pretty much identical with the `true`-case except for the returned
        // variant.
        scheduler.add_task_duration(Duration::milliseconds(time as i64), move |_| {
            let bot_msg = match msg.channel_id.say(&http, &args) {
                Ok(msg) => msg,
                Err(why) => {
                    println!("Error sending message: {:?}.", why);

                    return DateResult::Repeat(
                        Utc::now() + Duration::milliseconds(5000)
                    )
                },
            };
            let http = http.clone();

            dispatcher.write()
                .add_fn(DispatchEvent::ReactEvent(bot_msg.id, msg.author.id),
                    thanks_for_reacting(http, bot_msg.channel_id));

            // The task is done and that's it, we do not to repeat it.
            DateResult::Done
        });
    };

    Ok(())
}
<commit_msg>Update main.rs<commit_after>//! This example will showcase one way on how to extend Serenity with a
//! time-scheduler and an event-trigger-system.
//! We will create a remind-me command that will send a message after a
//! a demanded amount of time. Once the message has been sent, the user can
//! react to it, triggering an event to send another message.
use std::{collections::HashSet, env, hash::{Hash, Hasher},
    sync::Arc,
};
use serenity::{
    prelude::*,
    framework::standard::{
        Args, CommandResult, CommandGroup,
        DispatchError, HelpOptions, help_commands, StandardFramework,
        macros::{command, group, help},
    },
    http::Http,
    model::prelude::*,
};
// We will use this crate as event dispatcher.
use hey_listen::sync::{ParallelDispatcher as Dispatcher,
    ParallelDispatcherRequest as DispatcherRequest};
// And this crate to schedule our tasks.
use white_rabbit::{Utc, Scheduler, DateResult, Duration};

// This enum represents possible events a listener might wait for.
// In this case, we want to dispatch an event when a reaction is added.
// Serenity's event-enum is not suitable for this.
// First it offers too many variants we do not need, but most importantly,
// it lacks the `Default`-trait which makes sense
// as the enum-fields have no clear logical default value. But without it,
// constructing mock-variants becomes difficult.
//
// As a result, we make our own slick event-enum!
#[derive(Clone)]
enum DispatchEvent {
    ReactEvent(MessageId, UserId),
}

// We need to implement equality for our enum.
// One could test variants only. In this case, we want to know who reacted
// on which message.
impl PartialEq for DispatchEvent {
    fn eq(&self, other: &DispatchEvent) -> bool {
        match (self, other) {
            (DispatchEvent::ReactEvent(self_message_id, self_user_id),
            DispatchEvent::ReactEvent(other_message_id, other_user_id)) => {
                self_message_id == other_message_id &&
                self_user_id == other_user_id
            }
        }
    }
}

impl Eq for DispatchEvent {}

// See following Clippy-lint:
// https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
impl Hash for DispatchEvent {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            DispatchEvent::ReactEvent(msg_id, user_id) => {
                msg_id.hash(state);
                user_id.hash(state);
            }
        }
    }
}

struct DispatcherKey;
impl TypeMapKey for DispatcherKey {
    type Value = Arc<RwLock<Dispatcher<DispatchEvent>>>;
}

struct SchedulerKey;
impl TypeMapKey for SchedulerKey {
    type Value = Arc<RwLock<Scheduler>>;
}

struct Handler;
impl EventHandler for Handler {
    // We want to dispatch an event whenever a new reaction has been added.
    fn reaction_add(&self, context: Context, reaction: Reaction) {
        let dispatcher = {
            let mut context = context.data.write();
            context.get_mut::<DispatcherKey>().expect("Expected Dispatcher.").clone()
        };

        dispatcher.write().dispatch_event(
            &DispatchEvent::ReactEvent(reaction.message_id, reaction.user_id));
    }
}

group!({
    name: "remind_me",
    options: {
        prefixes: ["rm", "reminder"],
    },
    commands: [set_reminder],
});

#[help]
fn my_help(
    context: &mut Context,
    msg: &Message,
    args: Args,
    help_options: &'static HelpOptions,
    groups: &[&'static CommandGroup],
    owners: HashSet<UserId>
) -> CommandResult {
    help_commands::with_embeds(context, msg, args, &help_options, groups, owners)
}

fn main() {
    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN").expect(
        "Expected a token in the environment",
    );
    let mut client = Client::new(&token, Handler)
        .expect("Err creating client");

    {
        let mut data = client.data.write();
        // We create a new scheduler with 4 internal threads. Why 4? It really
        // is just an arbitrary number, you are often better setting this
        // based on your CPU.
        // When a task is due, a thread from the threadpool will be used to
        // avoid blocking the scheduler thread.
        let scheduler = Scheduler::new(4);
        let scheduler = Arc::new(RwLock::new(scheduler));

        let mut dispatcher: Dispatcher<DispatchEvent> = Dispatcher::default();
        // Once receiving an event to dispatch, the amount of threads
        // set via `num_threads` will dispatch in parallel.
        dispatcher.num_threads(4).expect("Could not construct threadpool");

        data.insert::<DispatcherKey>(Arc::new(RwLock::new(dispatcher)));
        data.insert::<SchedulerKey>(scheduler);
    }

    // We will fetch your bot's id.
    let bot_id = match client.cache_and_http.http.get_current_application_info() {
        Ok(info) => {
            info.id
        },
        Err(why) => panic!("Could not access application info: {:?}", why),
    };

    client.with_framework(
        // Configures the client, allowing for options to mutate how the
        // framework functions.
        StandardFramework::new()
        .configure(|c| c
            .with_whitespace(true)
            .on_mention(Some(bot_id))
            .prefix("~")
            .delimiters(vec![", ", ","]))
        .on_dispatch_error(|ctx, msg, error| {
            if let DispatchError::Ratelimited(seconds) = error {
                let _ = msg.channel_id.say(&ctx.http, &format!("Try this again in {} seconds.", seconds));
            }
        })
        .after(|_ctx, _msg, cmd_name, error| {

        if let Err(why) = error {
            println!("Error in {}: {:?}", cmd_name, why);
        }
    })
        .help(&MY_HELP)
        .group(&REMIND_ME_GROUP)
    );

    if let Err(why) = client.start() {
        println!("Client error: {:?}", why);
    }
}

// Just a helper-function for creating the closure we want to use as listener.
// It saves us from writing the same trigger twice for repeated and non-repeated
// tasks (see remind-me command below).
fn thanks_for_reacting(http: Arc<Http>, channel: ChannelId) ->
    Box<Fn(&DispatchEvent) -> Option<DispatcherRequest> + Send + Sync> {

    Box::new(move |_| {
        if let Err(why) = channel.say(&http, "Thanks for reacting!") {
            println!("Could not send message: {:?}", why);
        }

        Some(DispatcherRequest::StopListening)
    })
}

#[command]
#[aliases("add")]
fn set_reminder(context: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
    // It might be smart to set a moderately high minimum value for `time`
    // to avoid abuse like tasks that repeat every 100ms, especially since
    // channels have send-message rate limits.
    let time: u64 = args.single()?;
    let repeat: bool = args.single()?;
    let args = args.rest().to_string();

    let scheduler = {
        let mut context = context.data.write();
        context.get_mut::<SchedulerKey>().expect("Expected Scheduler.").clone()
    };

    let dispatcher = {
        let mut context = context.data.write();
        context.get_mut::<DispatcherKey>().expect("Expected Dispatcher.").clone()
    };

    let http = context.http.clone();
    let msg = msg.clone();

    let mut scheduler = scheduler.write();

    // First, we check if the user wants a repeated task or not.
    if repeat {
        // Chrono's duration can also be negative
        // and therefore we cast to `i64`.
        scheduler.add_task_duration(Duration::milliseconds(time as i64), move |_| {
            let bot_msg = match msg.channel_id.say(&http, &args) {
                Ok(msg) => msg,
                // We could not send the message, thus we will try sending it
                // again in five seconds.
                // It might be wise to keep a counter for maximum tries.
                // If the channel got deleted, trying to send a message will
                // always fail.
                Err(why) => {
                    println!("Error sending message: {:?}.", why);

                    return DateResult::Repeat(
                        Utc::now() + Duration::milliseconds(5000))
                },
            };

            let http = http.clone();

            // We add a function to dispatch for a certain event.
            dispatcher.write()
                .add_fn(DispatchEvent::ReactEvent(bot_msg.id, msg.author.id),
                    // The `thanks_for_reacting`-function creates a function
                    // to schedule.
                    thanks_for_reacting(http, bot_msg.channel_id));

            // We return that our date shall happen again, therefore we need
            // to tell when this shall be.
            DateResult::Repeat(Utc::now() + Duration::milliseconds(time as i64))
        });
    } else {
        // Pretty much identical with the `true`-case except for the returned
        // variant.
        scheduler.add_task_duration(Duration::milliseconds(time as i64), move |_| {
            let bot_msg = match msg.channel_id.say(&http, &args) {
                Ok(msg) => msg,
                Err(why) => {
                    println!("Error sending message: {:?}.", why);

                    return DateResult::Repeat(
                        Utc::now() + Duration::milliseconds(5000)
                    )
                },
            };
            let http = http.clone();

            dispatcher.write()
                .add_fn(DispatchEvent::ReactEvent(bot_msg.id, msg.author.id),
                    thanks_for_reacting(http, bot_msg.channel_id));

            // The task is done and that's it, we do not to repeat it.
            DateResult::Done
        });
    };

    Ok(())
}
<|endoftext|>


<commit_before>use std::task::{Context, Poll};

use futures::StreamExt;
use libp2p::core::connection::ConnectionId;
use libp2p::core::ConnectedPoint;
use libp2p::swarm::protocols_handler::DummyProtocolsHandler;
use libp2p::swarm::{
    DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler,
};
use libp2p::{Multiaddr, PeerId};
use slog::{debug, error};
use types::EthSpec;

use crate::metrics;
use crate::rpc::GoodbyeReason;
use crate::types::SyncState;

use super::peerdb::BanResult;
use super::{PeerManager, PeerManagerEvent, ReportSource};

impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
    type ProtocolsHandler = DummyProtocolsHandler;

    type OutEvent = PeerManagerEvent;

    /* Required trait members */

    fn new_handler(&mut self) -> Self::ProtocolsHandler {
        DummyProtocolsHandler::default()
    }

    fn inject_event(
        &mut self,
        _: PeerId,
        _: ConnectionId,
        _: <DummyProtocolsHandler as ProtocolsHandler>::OutEvent,
    ) {
        unreachable!("Dummy handler does not emit events")
    }

    fn poll(
        &mut self,
        cx: &mut Context<'_>,
        _params: &mut impl PollParameters,
    ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
        // perform the heartbeat when necessary
        while self.heartbeat.poll_tick(cx).is_ready() {
            self.heartbeat();
        }

        // poll the timeouts for pings and status'
        loop {
            match self.inbound_ping_peers.poll_next_unpin(cx) {
                Poll::Ready(Some(Ok(peer_id))) => {
                    self.inbound_ping_peers.insert(peer_id);
                    self.events.push(PeerManagerEvent::Ping(peer_id));
                }
                Poll::Ready(Some(Err(e))) => {
                    error!(self.log, "Failed to check for inbound peers to ping"; "error" => e.to_string())
                }
                Poll::Ready(None) | Poll::Pending => break,
            }
        }

        loop {
            match self.outbound_ping_peers.poll_next_unpin(cx) {
                Poll::Ready(Some(Ok(peer_id))) => {
                    self.outbound_ping_peers.insert(peer_id);
                    self.events.push(PeerManagerEvent::Ping(peer_id));
                }
                Poll::Ready(Some(Err(e))) => {
                    error!(self.log, "Failed to check for outbound peers to ping"; "error" => e.to_string())
                }
                Poll::Ready(None) | Poll::Pending => break,
            }
        }

        if !matches!(
            self.network_globals.sync_state(),
            SyncState::SyncingFinalized { .. } | SyncState::SyncingHead { .. }
        ) {
            loop {
                match self.status_peers.poll_next_unpin(cx) {
                    Poll::Ready(Some(Ok(peer_id))) => {
                        self.status_peers.insert(peer_id);
                        self.events.push(PeerManagerEvent::Status(peer_id))
                    }
                    Poll::Ready(Some(Err(e))) => {
                        error!(self.log, "Failed to check for peers to ping"; "error" => e.to_string())
                    }
                    Poll::Ready(None) | Poll::Pending => break,
                }
            }
        }

        if !self.events.is_empty() {
            return Poll::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0)));
        } else {
            self.events.shrink_to_fit();
        }

        Poll::Pending
    }

    /* Overwritten trait members */

    fn inject_connection_established(
        &mut self,
        peer_id: &PeerId,
        _connection_id: &ConnectionId,
        endpoint: &ConnectedPoint,
        _failed_addresses: Option<&Vec<Multiaddr>>,
    ) {
        debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => ?endpoint.to_endpoint());
        // Check NAT if metrics are enabled
        if self.network_globals.local_enr.read().udp().is_some() {
            metrics::check_nat();
        }

        // Check to make sure the peer is not supposed to be banned
        match self.ban_status(peer_id) {
            // TODO: directly emit the ban event?
            BanResult::BadScore => {
                // This is a faulty state
                error!(self.log, "Connecteded to a banned peer, re-banning"; "peer_id" => %peer_id);
                // Reban the peer
                self.goodbye_peer(peer_id, GoodbyeReason::Banned, ReportSource::PeerManager);
                return;
            }
            BanResult::BannedIp(ip_addr) => {
                // A good peer has connected to us via a banned IP address. We ban the peer and
                // prevent future connections.
                debug!(self.log, "Peer connected via banned IP. Banning"; "peer_id" => %peer_id, "banned_ip" => %ip_addr);
                self.goodbye_peer(peer_id, GoodbyeReason::BannedIP, ReportSource::PeerManager);
                return;
            }
            BanResult::NotBanned => {}
        }

        // Count dialing peers in the limit if the peer dialied us.
        let count_dialing = endpoint.is_listener();
        // Check the connection limits
        if self.peer_limit_reached(count_dialing)
            && self
                .network_globals
                .peers
                .read()
                .peer_info(peer_id)
                .map_or(true, |peer| !peer.has_future_duty())
        {
            // Gracefully disconnect the peer.
            self.disconnect_peer(*peer_id, GoodbyeReason::TooManyPeers);
            return;
        }

        // NOTE: We don't register peers that we are disconnecting immediately. The network service
        // does not need to know about these peers.
        match endpoint {
            ConnectedPoint::Listener { send_back_addr, .. } => {
                self.inject_connect_ingoing(peer_id, send_back_addr.clone(), None);
                self.events
                    .push(PeerManagerEvent::PeerConnectedIncoming(*peer_id));
            }
            ConnectedPoint::Dialer { address } => {
                self.inject_connect_outgoing(peer_id, address.clone(), None);
                self.events
                    .push(PeerManagerEvent::PeerConnectedOutgoing(*peer_id));
            }
        }

        // increment prometheus metrics
        self.update_connected_peer_metrics();
        metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
    }

    fn inject_disconnected(&mut self, peer_id: &PeerId) {
        // There are no more connections
        if self
            .network_globals
            .peers
            .read()
            .is_connected_or_disconnecting(peer_id)
        {
            // We are disconnecting the peer or the peer has already been connected.
            // Both these cases, the peer has been previously registered by the peer manager and
            // potentially the application layer.
            // Inform the application.
            self.events
                .push(PeerManagerEvent::PeerDisconnected(*peer_id));
            debug!(self.log, "Peer disconnected"; "peer_id" => %peer_id);
        }

        // NOTE: It may be the case that a rejected node, due to too many peers is disconnected
        // here and the peer manager has no knowledge of its connection. We insert it here for
        // reference so that peer manager can track this peer.
        self.inject_disconnect(peer_id);

        // Update the prometheus metrics
        self.update_connected_peer_metrics();
        metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
    }

    fn inject_address_change(
        &mut self,
        _peer_id: &PeerId,
        _connection_id: &ConnectionId,
        old: &ConnectedPoint,
        new: &ConnectedPoint,
    ) {
        debug_assert!(
            matches!(
                (old, new),
                (
                    // inbound remains inbound
                    ConnectedPoint::Listener { .. },
                    ConnectedPoint::Listener { .. }
                ) | (
                    // outbound remains outbound
                    ConnectedPoint::Dialer { .. },
                    ConnectedPoint::Dialer { .. }
                )
            ),
            "A peer has changed between inbound and outbound"
        )
    }

    /// A dial attempt has failed.
    ///
    /// NOTE: It can be the case that we are dialing a peer and during the dialing process the peer
    /// connects and the dial attempt later fails. To handle this, we only update the peer_db if
    /// the peer is not already connected.
    fn inject_dial_failure(
        &mut self,
        peer_id: Option<PeerId>,
        _handler: DummyProtocolsHandler,
        _error: &DialError,
    ) {
        if let Some(peer_id) = peer_id {
            if !self.network_globals.peers.read().is_connected(&peer_id) {
                self.inject_disconnect(&peer_id);
            }
        }
    }
}
<commit_msg>Fix small typo in error log (#2975)<commit_after>use std::task::{Context, Poll};

use futures::StreamExt;
use libp2p::core::connection::ConnectionId;
use libp2p::core::ConnectedPoint;
use libp2p::swarm::protocols_handler::DummyProtocolsHandler;
use libp2p::swarm::{
    DialError, NetworkBehaviour, NetworkBehaviourAction, PollParameters, ProtocolsHandler,
};
use libp2p::{Multiaddr, PeerId};
use slog::{debug, error};
use types::EthSpec;

use crate::metrics;
use crate::rpc::GoodbyeReason;
use crate::types::SyncState;

use super::peerdb::BanResult;
use super::{PeerManager, PeerManagerEvent, ReportSource};

impl<TSpec: EthSpec> NetworkBehaviour for PeerManager<TSpec> {
    type ProtocolsHandler = DummyProtocolsHandler;

    type OutEvent = PeerManagerEvent;

    /* Required trait members */

    fn new_handler(&mut self) -> Self::ProtocolsHandler {
        DummyProtocolsHandler::default()
    }

    fn inject_event(
        &mut self,
        _: PeerId,
        _: ConnectionId,
        _: <DummyProtocolsHandler as ProtocolsHandler>::OutEvent,
    ) {
        unreachable!("Dummy handler does not emit events")
    }

    fn poll(
        &mut self,
        cx: &mut Context<'_>,
        _params: &mut impl PollParameters,
    ) -> Poll<NetworkBehaviourAction<Self::OutEvent, Self::ProtocolsHandler>> {
        // perform the heartbeat when necessary
        while self.heartbeat.poll_tick(cx).is_ready() {
            self.heartbeat();
        }

        // poll the timeouts for pings and status'
        loop {
            match self.inbound_ping_peers.poll_next_unpin(cx) {
                Poll::Ready(Some(Ok(peer_id))) => {
                    self.inbound_ping_peers.insert(peer_id);
                    self.events.push(PeerManagerEvent::Ping(peer_id));
                }
                Poll::Ready(Some(Err(e))) => {
                    error!(self.log, "Failed to check for inbound peers to ping"; "error" => e.to_string())
                }
                Poll::Ready(None) | Poll::Pending => break,
            }
        }

        loop {
            match self.outbound_ping_peers.poll_next_unpin(cx) {
                Poll::Ready(Some(Ok(peer_id))) => {
                    self.outbound_ping_peers.insert(peer_id);
                    self.events.push(PeerManagerEvent::Ping(peer_id));
                }
                Poll::Ready(Some(Err(e))) => {
                    error!(self.log, "Failed to check for outbound peers to ping"; "error" => e.to_string())
                }
                Poll::Ready(None) | Poll::Pending => break,
            }
        }

        if !matches!(
            self.network_globals.sync_state(),
            SyncState::SyncingFinalized { .. } | SyncState::SyncingHead { .. }
        ) {
            loop {
                match self.status_peers.poll_next_unpin(cx) {
                    Poll::Ready(Some(Ok(peer_id))) => {
                        self.status_peers.insert(peer_id);
                        self.events.push(PeerManagerEvent::Status(peer_id))
                    }
                    Poll::Ready(Some(Err(e))) => {
                        error!(self.log, "Failed to check for peers to ping"; "error" => e.to_string())
                    }
                    Poll::Ready(None) | Poll::Pending => break,
                }
            }
        }

        if !self.events.is_empty() {
            return Poll::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0)));
        } else {
            self.events.shrink_to_fit();
        }

        Poll::Pending
    }

    /* Overwritten trait members */

    fn inject_connection_established(
        &mut self,
        peer_id: &PeerId,
        _connection_id: &ConnectionId,
        endpoint: &ConnectedPoint,
        _failed_addresses: Option<&Vec<Multiaddr>>,
    ) {
        debug!(self.log, "Connection established"; "peer_id" => %peer_id, "connection" => ?endpoint.to_endpoint());
        // Check NAT if metrics are enabled
        if self.network_globals.local_enr.read().udp().is_some() {
            metrics::check_nat();
        }

        // Check to make sure the peer is not supposed to be banned
        match self.ban_status(peer_id) {
            // TODO: directly emit the ban event?
            BanResult::BadScore => {
                // This is a faulty state
                error!(self.log, "Connected to a banned peer, re-banning"; "peer_id" => %peer_id);
                // Reban the peer
                self.goodbye_peer(peer_id, GoodbyeReason::Banned, ReportSource::PeerManager);
                return;
            }
            BanResult::BannedIp(ip_addr) => {
                // A good peer has connected to us via a banned IP address. We ban the peer and
                // prevent future connections.
                debug!(self.log, "Peer connected via banned IP. Banning"; "peer_id" => %peer_id, "banned_ip" => %ip_addr);
                self.goodbye_peer(peer_id, GoodbyeReason::BannedIP, ReportSource::PeerManager);
                return;
            }
            BanResult::NotBanned => {}
        }

        // Count dialing peers in the limit if the peer dialied us.
        let count_dialing = endpoint.is_listener();
        // Check the connection limits
        if self.peer_limit_reached(count_dialing)
            && self
                .network_globals
                .peers
                .read()
                .peer_info(peer_id)
                .map_or(true, |peer| !peer.has_future_duty())
        {
            // Gracefully disconnect the peer.
            self.disconnect_peer(*peer_id, GoodbyeReason::TooManyPeers);
            return;
        }

        // NOTE: We don't register peers that we are disconnecting immediately. The network service
        // does not need to know about these peers.
        match endpoint {
            ConnectedPoint::Listener { send_back_addr, .. } => {
                self.inject_connect_ingoing(peer_id, send_back_addr.clone(), None);
                self.events
                    .push(PeerManagerEvent::PeerConnectedIncoming(*peer_id));
            }
            ConnectedPoint::Dialer { address } => {
                self.inject_connect_outgoing(peer_id, address.clone(), None);
                self.events
                    .push(PeerManagerEvent::PeerConnectedOutgoing(*peer_id));
            }
        }

        // increment prometheus metrics
        self.update_connected_peer_metrics();
        metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
    }

    fn inject_disconnected(&mut self, peer_id: &PeerId) {
        // There are no more connections
        if self
            .network_globals
            .peers
            .read()
            .is_connected_or_disconnecting(peer_id)
        {
            // We are disconnecting the peer or the peer has already been connected.
            // Both these cases, the peer has been previously registered by the peer manager and
            // potentially the application layer.
            // Inform the application.
            self.events
                .push(PeerManagerEvent::PeerDisconnected(*peer_id));
            debug!(self.log, "Peer disconnected"; "peer_id" => %peer_id);
        }

        // NOTE: It may be the case that a rejected node, due to too many peers is disconnected
        // here and the peer manager has no knowledge of its connection. We insert it here for
        // reference so that peer manager can track this peer.
        self.inject_disconnect(peer_id);

        // Update the prometheus metrics
        self.update_connected_peer_metrics();
        metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
    }

    fn inject_address_change(
        &mut self,
        _peer_id: &PeerId,
        _connection_id: &ConnectionId,
        old: &ConnectedPoint,
        new: &ConnectedPoint,
    ) {
        debug_assert!(
            matches!(
                (old, new),
                (
                    // inbound remains inbound
                    ConnectedPoint::Listener { .. },
                    ConnectedPoint::Listener { .. }
                ) | (
                    // outbound remains outbound
                    ConnectedPoint::Dialer { .. },
                    ConnectedPoint::Dialer { .. }
                )
            ),
            "A peer has changed between inbound and outbound"
        )
    }

    /// A dial attempt has failed.
    ///
    /// NOTE: It can be the case that we are dialing a peer and during the dialing process the peer
    /// connects and the dial attempt later fails. To handle this, we only update the peer_db if
    /// the peer is not already connected.
    fn inject_dial_failure(
        &mut self,
        peer_id: Option<PeerId>,
        _handler: DummyProtocolsHandler,
        _error: &DialError,
    ) {
        if let Some(peer_id) = peer_id {
            if !self.network_globals.peers.read().is_connected(&peer_id) {
                self.inject_disconnect(&peer_id);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rusoto;
extern crate xml;

use xml::reader::*;
use rusoto::xmlutil::*;
use std::io::prelude::*;
use std::path::Path;
use std::io::BufReader;
use std::fs::File;
use std::fs;
use std::error::Error;
use std::iter::Peekable;
use xml::reader::events::*;

#[test]
fn peek_at_name_happy_path() {
    // open file
    let mut good_xml = open_xmlfile_for_test("tests/sampledata/sqs-happy.xml");
    // try peek_at_name

    match peek_at_name(&mut good_xml) {
        Ok(data) => println!("Got {}", data),
        Err(why) => panic!("Couldn't peek at name")
    }
}

fn open_xmlfile_for_test<'a>(file_location: &str) -> XmlResponseFromFile {
    let file = File::open(file_location).unwrap();
    let file = BufReader::new(file);

    let mut parser = EventReader::new(file);
    let mut XmlResponse = XmlResponseFromFile::new(parser.events().peekable());
    return XmlResponse;
}

pub struct XmlResponseFromFile<'a> {
	xml_stack: Peekable<Events<'a, BufReader<File>>>,
}

// I cannot explain how these lifetimes work to a child, therefore I need to understand them better:
impl <'a>XmlResponseFromFile<'a> {
	pub fn new<'c>(stack: Peekable<Events<'a, BufReader<File>>>) -> XmlResponseFromFile {
		XmlResponseFromFile {
			xml_stack: stack,
		}
	}
}

// Need peek and next implemented.
impl <'b> Peek for XmlResponseFromFile <'b> {
	fn peek(&mut self) -> Option<&XmlEvent> {
		return self.xml_stack.peek();
	}
}

impl <'b> Next for XmlResponseFromFile <'b> {
	fn next(&mut self) -> Option<XmlEvent> {
		return self.xml_stack.next();
	}
}
<commit_msg>Refactors xmlutils test to have less borrow checker grumpiness.<commit_after>extern crate rusoto;
extern crate xml;

use xml::reader::*;
use rusoto::xmlutil::*;
use std::io::prelude::*;
use std::path::Path;
use std::io::BufReader;
use std::fs::File;
use std::fs;
use std::error::Error;
use std::iter::Peekable;
use xml::reader::events::*;

#[test]
fn peek_at_name_happy_path() {
    // open file
    let file = File::open("tests/blah.xml").unwrap();
    let file = BufReader::new(file);

    let mut my_parser  = EventReader::new(file);
    let mut my_stack = my_parser.events().peekable();

    let mut reader = XmlResponseFromFile::new(my_stack);

    // try peek_at_name
    match peek_at_name(&mut reader) {
        Ok(data) => println!("Got {}", data),
        Err(why) => panic!("Couldn't peek at name")
    }
}

pub struct XmlResponseFromFile<'a> {
	xml_stack: Peekable<Events<'a, BufReader<File>>>,
}

// I cannot explain how these lifetimes work to a child, therefore I need to understand them better:
impl <'a>XmlResponseFromFile<'a> {
	pub fn new<'c>(my_stack: Peekable<Events<'a, BufReader<File>>>) -> XmlResponseFromFile {
		return XmlResponseFromFile { xml_stack: my_stack };
	}
}

// Need peek and next implemented.
impl <'b> Peek for XmlResponseFromFile <'b> {
	fn peek(&mut self) -> Option<&XmlEvent> {
		return self.xml_stack.peek();
	}
}

impl <'b> Next for XmlResponseFromFile <'b> {
	fn next(&mut self) -> Option<XmlEvent> {
		return self.xml_stack.next();
	}
}
<|endoftext|>


<commit_before>extern crate perfcnt;

use std::io::Result;
use perfcnt::{PerfCounter, AbstractPerfCounter};
use perfcnt::linux::{SoftwareEventType, PerfCounterBuilderLinux, CacheId, CacheOpId, CacheOpResultId, HardwareEventType, SamplingPerfCounter};

//#[test]
pub fn sample_event() {
    let pc: PerfCounter = PerfCounterBuilderLinux::from_software_event(SoftwareEventType::CpuClock)
        .set_sample_frequency(10000)
        .set_ip_sample_zero_skid()
        .enable_mmap()
        .enable_mmap_data()
        .finish()
        .expect("Could not create counter");

    pc.start().expect("Can not start the counter");
    println!("asdf");
    println!("asdf");
    println!("asdf");
    println!("asdf");
    println!("asdf");

    let spc = SamplingPerfCounter::new(pc);

    for e in spc {
        println!("{:?}", e);
    }
}

#[test]
pub fn test_cache_events() {
    let ret: Result<PerfCounter> = PerfCounterBuilderLinux::from_cache_event(CacheId::L1D, CacheOpId::Read, CacheOpResultId::Miss)
                 .finish();

    match ret {
        Ok(mut pc) => {
            pc.start().expect("Can not start the counter");
            pc.stop().expect("Can not stop the counter");
            let res = pc.read().expect("Can not read the counter");
            assert!(res > 0);
        }
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 2)
    }
}

#[test]
pub fn test_hardware_counter() {
    let ret: Result<PerfCounter> = PerfCounterBuilderLinux::from_hardware_event(HardwareEventType::CacheMisses)
        .exclude_kernel()
        .exclude_idle()
        .finish();

    match ret {
        Ok(mut pc) => {
            pc.reset().expect("Can not reset");
            pc.start().expect("Can not stop the counter");
            pc.stop().expect("Can not start the counter");
            let res = pc.read().expect("Can not read the counter");
            assert!(res < 100);
        }
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 2)
    }
}
/*

#[test]
pub fn test_software_events() {
    let mut pc: PerfCounter = PerfCounterBuilderLinux::from_software_event(SoftwareEventType::PageFaults)
        .exclude_idle()
        .exclude_kernel()
        .add_read_format(ReadFormat::TotalTimeEnabled)
        .add_read_format(ReadFormat::TotalTimeRunning)
        .add_read_format(ReadFormat::FormatId)
        .finish()
        .expect("Could not create counter");

    let size = 1024*1024*16;
    let page_size = 4096;
    let p: *mut u8 = unsafe {
        // Make sure the buffer is big enough such that it is going to be
        // mmaped and not coming from some pre-allocated buffers
        allocate(size, page_size)
    };

    pc.reset().expect("Can not reset");
    pc.start().expect("Can not start the counter");
    // Touch two pages:
    unsafe {
        std::ptr::write(p, 0x1);
        std::ptr::write(p.offset(((size/page_size/2)*page_size) as isize), 0x01);
    }
    pc.stop().expect("Can not stop the counter");

    // Should be ~= 2
    let res = pc.read_fd().expect("Can not read the counter");
    assert_eq!(res.value, 2);
}*/
<commit_msg>Update test to reflect new errno<commit_after>extern crate perfcnt;

use std::io::Result;
use perfcnt::{PerfCounter, AbstractPerfCounter};
use perfcnt::linux::{SoftwareEventType, PerfCounterBuilderLinux, CacheId, CacheOpId, CacheOpResultId, HardwareEventType, SamplingPerfCounter};

//#[test]
pub fn sample_event() {
    let pc: PerfCounter = PerfCounterBuilderLinux::from_software_event(SoftwareEventType::CpuClock)
        .set_sample_frequency(10000)
        .set_ip_sample_zero_skid()
        .enable_mmap()
        .enable_mmap_data()
        .finish()
        .expect("Could not create counter");

    pc.start().expect("Can not start the counter");
    println!("asdf");
    println!("asdf");
    println!("asdf");
    println!("asdf");
    println!("asdf");

    let spc = SamplingPerfCounter::new(pc);

    for e in spc {
        println!("{:?}", e);
    }
}

#[test]
pub fn test_cache_events() {
    let ret: Result<PerfCounter> = PerfCounterBuilderLinux::from_cache_event(CacheId::L1D, CacheOpId::Read, CacheOpResultId::Miss)
                 .finish();

    match ret {
        Ok(mut pc) => {
            pc.start().expect("Can not start the counter");
            pc.stop().expect("Can not stop the counter");
            let res = pc.read().expect("Can not read the counter");
            assert!(res > 0);
        }
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 13)
    }
}

#[test]
pub fn test_hardware_counter() {
    let ret: Result<PerfCounter> = PerfCounterBuilderLinux::from_hardware_event(HardwareEventType::CacheMisses)
        .exclude_kernel()
        .exclude_idle()
        .finish();

    match ret {
        Ok(mut pc) => {
            pc.reset().expect("Can not reset");
            pc.start().expect("Can not stop the counter");
            pc.stop().expect("Can not start the counter");
            let res = pc.read().expect("Can not read the counter");
            assert!(res < 100);
        }
        Err(e) => assert_eq!(e.raw_os_error().unwrap(), 2)
    }
}
/*

#[test]
pub fn test_software_events() {
    let mut pc: PerfCounter = PerfCounterBuilderLinux::from_software_event(SoftwareEventType::PageFaults)
        .exclude_idle()
        .exclude_kernel()
        .add_read_format(ReadFormat::TotalTimeEnabled)
        .add_read_format(ReadFormat::TotalTimeRunning)
        .add_read_format(ReadFormat::FormatId)
        .finish()
        .expect("Could not create counter");

    let size = 1024*1024*16;
    let page_size = 4096;
    let p: *mut u8 = unsafe {
        // Make sure the buffer is big enough such that it is going to be
        // mmaped and not coming from some pre-allocated buffers
        allocate(size, page_size)
    };

    pc.reset().expect("Can not reset");
    pc.start().expect("Can not start the counter");
    // Touch two pages:
    unsafe {
        std::ptr::write(p, 0x1);
        std::ptr::write(p.offset(((size/page_size/2)*page_size) as isize), 0x01);
    }
    pc.stop().expect("Can not stop the counter");

    // Should be ~= 2
    let res = pc.read_fd().expect("Can not read the counter");
    assert_eq!(res.value, 2);
}*/
<|endoftext|>


<commit_before>#![cfg(all(
    not(target_os = "fuchsia"),
    not(target_os = "android"),
    not(target_os = "windows"),
    not(target_os = "macos")
))]

extern crate libc;
extern crate pagecache;
extern crate rand;
extern crate sled;
extern crate tests;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 256;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    tests::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = sled::Db::start(config).unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.insert(&key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .async_io(true)
        .io_bufs(2)
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .async_io(true)
        .io_bufs(2)
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(5000)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
#[ignore]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
#[ignore]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<commit_msg>Remove io_bufs configuration from crash test<commit_after>#![cfg(all(
    not(target_os = "fuchsia"),
    not(target_os = "android"),
    not(target_os = "windows"),
    not(target_os = "macos")
))]

extern crate libc;
extern crate pagecache;
extern crate rand;
extern crate sled;
extern crate tests;

use std::fs;
use std::mem::size_of;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 256;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (_k, v) = res.unwrap();
        if &v[..4] == &highest_vec[..4] {
            contiguous += 1;
        } else {
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.range(&*low_beginning..) {
        let (k, v): (sled::IVec, _) = res.unwrap();
        assert_eq!(
            slice_to_u32(&*v),
            lowest,
            "expected key {} to have value {}, instead it had value {} in db: {:?}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v),
            tree
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; size_of::<u32>()] = u.to_be_bytes();
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; size_of::<u32>()];
    buf.copy_from_slice(&b[..size_of::<u32>()]);

    u32::from_be_bytes(buf)
}

fn spawn_killah() {
    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });
}

fn run(config: Config) {
    tests::setup_logger();
    let crash_during_initialization = rand::thread_rng().gen_bool(0.1);

    if crash_during_initialization {
        spawn_killah();
    }

    let tree = sled::Db::start(config).unwrap();

    if !crash_during_initialization {
        spawn_killah();
    }

    let (key, highest) = verify(&tree);

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let key = u32_to_vec((hu % CYCLE) as u32);

        let mut value = u32_to_vec((hu / CYCLE) as u32);
        let additional_len = rand::thread_rng().gen_range(0, 1000);
        value.append(&mut vec![0u8; additional_len]);

        tree.insert(&key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .async_io(true)
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .async_io(true)
        .page_consolidation_threshold(10)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        .io_buf_size(1_000)
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(5000)
        .build();

    match thread::spawn(|| run(config)).join() {
        Err(e) => {
            println!("worker thread failed: {:?}", e);
            std::process::exit(15);
        }
        _ => {}
    }
}

#[test]
#[ignore]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
#[ignore]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        fs::remove_dir_all(dir).unwrap();
    }
}
<|endoftext|>


<commit_before>/* Implements monte carlo tree search

From PROGRESSIVE STRATEGIES FOR MONTE-CARLO TREE SEARCH,
which was linked in the Wikipedia.
(https://dke.maastrichtuniversity.nl/m.winands/documents/pMCTS.pdf)

Selection: start from root R and select successive child nodes down to a leaf node L.
Expansion: unless L ends the game with a win/loss for either player, create child nodes.
Simulation: play a random playout from node C.
Backpropagation: use the result of the playout to update information in the nodes.

*/

use rand::{thread_rng, Rng};

use ai::StatelessAI;
use game;
use game::Position2;

pub struct MCTreeAI {
    endurance: usize,
    exploration: f32,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct Index(usize);

// Using a VecTree strategy to sidestep the borrow checker.
// Doing anything tree based, especially with back references to parents
// always involves struggling against the borrowck.
// This is basically implementing pointers by hand. But propper
// livetime checking or garbage collection is only necessary when
// objects ever get deleted. That doesn't happen here.
struct VecTree {
    storage: Vec<Node>,
}

impl VecTree {
    fn new(capacity: usize, state: &game::State) -> Self {
        let mut storage = Vec::with_capacity(capacity);
        storage.push(Node::new(None, state));
        VecTree { storage }
    }
    fn robust_move(&self) -> Position2 {
        // Select the action, which was played most often. Apparently this
        // is more robust than using the action with the best win ratio.
        let ref root = self.storage[0];

        let mut most_robust = vec![];
        let mut most_simulations = 0;

        for i in 0..16 {
            match root.children[i] {
                ChildRef::Expanded(child_index) => {
                    let ref child = self.storage[child_index.0];
                    if child.simulation_count > most_simulations {
                        most_robust = vec![i];
                        most_simulations = child.simulation_count;
                    } else if child.simulation_count == most_simulations {
                        most_robust.push(i);
                    } else {
                        // This child is worse than a previously seen child.
                    }
                }
                _ => {}
            }
        }

        let choosen_position = *thread_rng().choose(&most_robust).unwrap();

        // Finally, we got the best move - return it to play it.
        Position2(choosen_position as u8)
    }
}

struct Node {
    // The win_count counts wins - losses and can be negative.
    win_count: isize,
    simulation_count: usize,

    parent: Option<Index>,
    children: [ChildRef; 16],
}

impl Node {
    fn new(parent_index: Option<Index>, state: &game::State) -> Self {
        let mut children = [ChildRef::NotYetExpanded; 16];
        for i in 0..16 {
            if state.column_height[i] == 4 {
                children[i] = ChildRef::IllegalMove;
            }
        }
        Node {
            win_count: 0,
            simulation_count: 0,
            parent: parent_index,
            children,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ChildRef {
    IllegalMove,
    NotYetExpanded,
    Expanded(Index),
}

impl VecTree {
    fn select_best(
        &mut self,
        node_index: Index,
        mut state: game::State,
        exploration: f32,
    ) -> (Index, game::State) {
        use std::f32;

        if !state.victory_state.active() {
            return (node_index, state);
        }

        let mut candidates: Vec<usize> = vec![];
        let mut best_value: f32 = f32::NEG_INFINITY;

        for i in 0..16 {
            match self.storage[node_index.0].children[i] {
                ChildRef::IllegalMove => {}
                ChildRef::NotYetExpanded => {
                    return self.initialize_random_child(node_index, i, state);
                }
                ChildRef::Expanded(child_index) => {
                    let ref node = self.storage[node_index.0];
                    let ref child = self.storage[child_index.0];

                    let exploitation_value = child.win_count as f32 / child.simulation_count as f32;
                    let exploration_value = exploration *
                        f32::sqrt(
                            f32::ln(node.simulation_count as f32) / child.simulation_count as f32,
                        );

                    let value = exploration_value + exploitation_value;

                    if value > best_value {
                        best_value = value;
                        candidates = vec![i];
                    } else if value == best_value {
                        candidates.push(i);
                    } else {
                        // Do nothing, this child doesn't qualify for the random draw.
                    }
                }
            }
        }

        // TODO: We can only sensibly unwrap, if we make sure that
        // the game is still ongoing at this moment.
        let choosen_position = *thread_rng().choose(&candidates).unwrap_or_else(|| {
            panic!("Trying to choose a best child when no children are avaliable.")
        });

        state.execute(Position2(choosen_position as u8));

        if let ChildRef::Expanded(child_index) =
            self.storage[node_index.0].children[choosen_position]
        {

            self.select_best(child_index, state, exploration)

        } else {
            // The choosen_position is drawn from indices
            // where an expanded child is guaranteed to exist.
            panic!("The choosen child somehow isn't expanded.");
        }
    }
    // Selects and initializes an uninitialized move.
    fn initialize_random_child(
        &mut self,
        node_index: Index,
        first_uninitialized_child_index: usize,
        mut state: game::State,
    ) -> (Index, game::State) {
        let new_index = Index(self.storage.len());

        let choosen_position = {
            // To satisfy borrowck, I first mutate the parent node itself,
            // then drop the mutable reference to it and add the new child
            // to the vector which also contains the node.
            // Borrowck rightfully complains about this, because adding a child
            // might reallocate the whole vector, rendering the node pointer invalid.
            let ref mut node = self.storage[node_index.0];

            let mut uninitialized_children = vec![first_uninitialized_child_index];
            for i in (first_uninitialized_child_index + 1)..16 {
                if node.children[i] == ChildRef::NotYetExpanded {
                    uninitialized_children.push(i);
                }
            }

            let choosen_position = *thread_rng().choose(&uninitialized_children).unwrap();

            node.children[choosen_position] = ChildRef::Expanded(new_index);
            choosen_position
        };

        state.execute(Position2(choosen_position as u8));
        self.storage.push(Node::new(Some(node_index), &state));

        (new_index, state)
    }
    fn backpropagate(&mut self, node_index: Index, value: isize) {
        if let Some(parent_index) =
            {
                // This is wrapped in { .. } in order to drop the mutable reference
                // to the node before using &mut self again.
                let ref mut node = self.storage[node_index.0];
                node.win_count += value;
                node.simulation_count += 1;
                node.parent
            }
        {
            self.backpropagate(parent_index, -value);
        }

    }
}

impl MCTreeAI {
    pub fn new(endurance: usize, exploration: f32) -> Self {
        MCTreeAI {
            endurance,
            exploration,
        }
    }
    fn create_tree_async(&self, state: &game::State) -> VecTree {
        use ai::mc::random_playout;
        use threadpool::ThreadPool;
        use std::sync::mpsc::channel;

        // Set up everything async.
        let worker_count = 4;
        let pool = ThreadPool::new(worker_count);
        let (sender, receiver) = channel();

        // Set up an empty tree.
        let mut tree = VecTree::new(self.endurance + 1, state);
        assert!(
            self.endurance > worker_count,
            "The endurance must be larger than {}.",
            worker_count
        );
        let mut endurance_left = self.endurance - worker_count;

        // Create the first few packages worth of work.
        for _ in 0..worker_count {
            // Selection & Expansion
            let (leaf_index, leaf_state) =
                tree.select_best(Index(0), state.clone(), self.exploration);

            // Simulation
            let sender_clone = sender.clone();
            pool.execute(move || {
                let current_color = leaf_state.current_color;
                let score = random_playout(leaf_state).scoring(current_color).unwrap() as isize;

                sender_clone.send((leaf_index, score)).unwrap();
            });
        }

        // Now wait for results
        while let Ok((leaf_index, score)) = receiver.recv() {
            // Backpropagation
            tree.backpropagate(leaf_index, -score);

            if endurance_left > 0 {
                endurance_left -= 1;
                // Generate new work
                // Selection & Expansion
                let (leaf_index, leaf_state) =
                    tree.select_best(Index(0), state.clone(), self.exploration);

                // Simulation
                let sender_clone = sender.clone();
                pool.execute(move || {
                    let current_color = leaf_state.current_color;
                    let score = random_playout(leaf_state).scoring(current_color).unwrap() as isize;

                    sender_clone.send((leaf_index, score)).unwrap();
                });
            } else if pool.active_count() == 0 {
                break;
            }
        }

        tree
    }
}

impl StatelessAI for MCTreeAI {
    fn action(&self, state: &game::State) -> Position2 {
        self.create_tree_async(state).robust_move()
    }
}
<commit_msg>Clean up multithreading & fix a (non-critical) race condition.<commit_after>/* Implements monte carlo tree search

From PROGRESSIVE STRATEGIES FOR MONTE-CARLO TREE SEARCH,
which was linked in the Wikipedia.
(https://dke.maastrichtuniversity.nl/m.winands/documents/pMCTS.pdf)

Selection: start from root R and select successive child nodes down to a leaf node L.
Expansion: unless L ends the game with a win/loss for either player, create child nodes.
Simulation: play a random playout from node C.
Backpropagation: use the result of the playout to update information in the nodes.

*/

use rand::{thread_rng, Rng};

use ai::StatelessAI;
use game;
use game::Position2;

use std::sync::mpsc::{channel, Sender};
use threadpool::ThreadPool;

pub struct MCTreeAI {
    endurance: usize,
    exploration: f32,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
struct Index(usize);

// Using a VecTree strategy to sidestep the borrow checker.
// Doing anything tree based, especially with back references to parents
// always involves struggling against the borrowck.
// This is basically implementing pointers by hand. But propper
// livetime checking or garbage collection is only necessary when
// objects ever get deleted. That doesn't happen here.
struct VecTree {
    storage: Vec<Node>,
}

impl VecTree {
    fn new(capacity: usize, state: &game::State) -> Self {
        let mut storage = Vec::with_capacity(capacity);
        storage.push(Node::new(None, state));
        VecTree { storage }
    }
    fn robust_move(&self) -> Position2 {
        // Select the action, which was played most often. Apparently this
        // is more robust than using the action with the best win ratio.
        let ref root = self.storage[0];

        let mut most_robust = vec![];
        let mut most_simulations = 0;

        for i in 0..16 {
            match root.children[i] {
                ChildRef::Expanded(child_index) => {
                    let ref child = self.storage[child_index.0];
                    if child.simulation_count > most_simulations {
                        most_robust = vec![i];
                        most_simulations = child.simulation_count;
                    } else if child.simulation_count == most_simulations {
                        most_robust.push(i);
                    } else {
                        // This child is worse than a previously seen child.
                    }
                }
                _ => {}
            }
        }

        let choosen_position = *thread_rng().choose(&most_robust).unwrap();

        // Finally, we got the best move - return it to play it.
        Position2(choosen_position as u8)
    }
}

struct Node {
    // The win_count counts wins - losses and can be negative.
    win_count: isize,
    simulation_count: usize,

    parent: Option<Index>,
    children: [ChildRef; 16],
}

impl Node {
    fn new(parent_index: Option<Index>, state: &game::State) -> Self {
        let mut children = [ChildRef::NotYetExpanded; 16];
        for i in 0..16 {
            if state.column_height[i] == 4 {
                children[i] = ChildRef::IllegalMove;
            }
        }
        Node {
            win_count: 0,
            simulation_count: 0,
            parent: parent_index,
            children,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ChildRef {
    IllegalMove,
    NotYetExpanded,
    Expanded(Index),
}

impl VecTree {
    fn select_best(
        &mut self,
        node_index: Index,
        mut state: game::State,
        exploration: f32,
    ) -> (Index, game::State) {
        use std::f32;

        if !state.victory_state.active() {
            return (node_index, state);
        }

        let mut candidates: Vec<usize> = vec![];
        let mut best_value: f32 = f32::NEG_INFINITY;

        for i in 0..16 {
            match self.storage[node_index.0].children[i] {
                ChildRef::IllegalMove => {}
                ChildRef::NotYetExpanded => {
                    return self.initialize_random_child(node_index, i, state);
                }
                ChildRef::Expanded(child_index) => {
                    let ref node = self.storage[node_index.0];
                    let ref child = self.storage[child_index.0];

                    let exploitation_value = child.win_count as f32 / child.simulation_count as f32;
                    let exploration_value = exploration *
                        f32::sqrt(
                            f32::ln(node.simulation_count as f32) / child.simulation_count as f32,
                        );

                    let value = exploration_value + exploitation_value;

                    if value > best_value {
                        best_value = value;
                        candidates = vec![i];
                    } else if value == best_value {
                        candidates.push(i);
                    } else {
                        // Do nothing, this child doesn't qualify for the random draw.
                    }
                }
            }
        }

        // TODO: We can only sensibly unwrap, if we make sure that
        // the game is still ongoing at this moment.
        let choosen_position = *thread_rng().choose(&candidates).unwrap_or_else(|| {
            panic!("Trying to choose a best child when no children are avaliable.")
        });

        state.execute(Position2(choosen_position as u8));

        if let ChildRef::Expanded(child_index) =
            self.storage[node_index.0].children[choosen_position]
        {

            self.select_best(child_index, state, exploration)

        } else {
            // The choosen_position is drawn from indices
            // where an expanded child is guaranteed to exist.
            panic!("The choosen child somehow isn't expanded.");
        }
    }
    // Selects and initializes an uninitialized move.
    fn initialize_random_child(
        &mut self,
        node_index: Index,
        first_uninitialized_child_index: usize,
        mut state: game::State,
    ) -> (Index, game::State) {
        let new_index = Index(self.storage.len());

        let choosen_position = {
            // To satisfy borrowck, I first mutate the parent node itself,
            // then drop the mutable reference to it and add the new child
            // to the vector which also contains the node.
            // Borrowck rightfully complains about this, because adding a child
            // might reallocate the whole vector, rendering the node pointer invalid.
            let ref mut node = self.storage[node_index.0];

            let mut uninitialized_children = vec![first_uninitialized_child_index];
            for i in (first_uninitialized_child_index + 1)..16 {
                if node.children[i] == ChildRef::NotYetExpanded {
                    uninitialized_children.push(i);
                }
            }

            let choosen_position = *thread_rng().choose(&uninitialized_children).unwrap();

            node.children[choosen_position] = ChildRef::Expanded(new_index);
            choosen_position
        };

        state.execute(Position2(choosen_position as u8));
        self.storage.push(Node::new(Some(node_index), &state));

        (new_index, state)
    }
    fn backpropagate(&mut self, node_index: Index, value: isize) {
        if let Some(parent_index) =
            {
                // This is wrapped in { .. } in order to drop the mutable reference
                // to the node before using &mut self again.
                let ref mut node = self.storage[node_index.0];
                node.win_count += value;
                node.simulation_count += 1;
                node.parent
            }
        {
            self.backpropagate(parent_index, -value);
        }

    }
}

impl MCTreeAI {
    pub fn new(endurance: usize, exploration: f32) -> Self {
        MCTreeAI {
            endurance,
            exploration,
        }
    }
    fn create_tree_async(&self, state: &game::State) -> VecTree {
        // Set up everything async.
        let worker_count = 4;
        let pool = ThreadPool::new(worker_count);

        // Set up an empty tree.
        let mut tree = VecTree::new(self.endurance + 1, state);
        assert!(
            self.endurance > worker_count,
            "The endurance must be larger than {}.",
            worker_count
        );
        let mut endurance_left = self.endurance - worker_count;

        let receiver = {
            // We need to drop all senders for the receiver to close.
            // After there is no more work to assign, the sender is dropped
            // at the end of this scope.
            let (sender, receiver) = channel();

            // Create the first few packages worth of work.
            for _ in 0..worker_count {
                self.create_simulation_task(&mut tree, state, &sender, &pool);
            }

            // Now wait for results, create new work to replace it.
            while let Ok((leaf_index, score)) = receiver.recv() {
                // Backpropagation
                tree.backpropagate(leaf_index, -score);

                if endurance_left > 0 {
                    endurance_left -= 1;
                    self.create_simulation_task(&mut tree, state, &sender, &pool);
                } else {
                    break;
                }
            }
            receiver
        };

        // Wait for the very last results
        while let Ok((leaf_index, score)) = receiver.recv() {
            tree.backpropagate(leaf_index, -score);
        }

        tree
    }
    fn create_simulation_task(
        &self,
        tree: &mut VecTree,
        state: &game::State,
        sender: &Sender<(Index, isize)>,
        pool: &ThreadPool,
    ) {
        use ai::mc::random_playout;
        // Selection & Expansion
        let (leaf_index, leaf_state) = tree.select_best(Index(0), state.clone(), self.exploration);

        // Simulation
        let sender_clone = sender.clone();
        pool.execute(move || {
            let current_color = leaf_state.current_color;
            let score = random_playout(leaf_state).scoring(current_color).unwrap() as isize;

            sender_clone.send((leaf_index, score)).unwrap();
        });
    }
}

impl StatelessAI for MCTreeAI {
    fn action(&self, state: &game::State) -> Position2 {
        self.create_tree_async(state).robust_move()
    }
}
<|endoftext|>


<commit_before>pub mod compartment;
pub mod ref_manip;

#[cfg(test)]
mod tests {
    use super::*;
    use js_types::js_type::{JsT, JsType};
    use js_types::js_obj::JsObjStruct;
    use js_types::js_str::JsStrStruct;
    use alloc::compartment::Compartment;
    use alloc::ref_manip::StackFrame;

    #[test]
    fn test_alloc() {
        let comp = Compartment::new("test");
        let mut frame = StackFrame::new();
        let test_obj = JsT::new(
                        JsType::JsObj(
                        JsObjStruct::new(None, "test_obj",
                                         vec![(JsT::new(JsType::JsStr(JsStrStruct::new("a"))),
                                               JsT::new(JsType::JsNum(1.0f64)))])));
        let obj_ref = comp.alloc_inside(test_obj);
        frame.alloc_ref(obj_ref);
    }
}
<commit_msg>Remove outdated tests from alloc/mod.rs<commit_after>pub mod compartment;
pub mod ref_manip;

#[cfg(test)]
mod tests {
    use super::*;
    use js_types::js_type::{JsT, JsType};
    use js_types::js_obj::JsObjStruct;
    use js_types::js_str::JsStrStruct;
}
<|endoftext|>