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

use resource_task::{LoadResponse, LoadData};
use http_loader;
use http::headers::HeaderEnum;
use servo_util::task::spawn_named;
use std::ascii::AsciiExt;
use std::comm::{channel, Sender};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    spawn_named("ws_loader", proc() load(load_data, start_chan))
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {

    let(sen,rec)=channel();
    http_loader::load(load_data, sen);
    let response=rec.recv();
    let mut flag: int = 0;
    response.metadata.headers.as_ref().map(|headers| {
        let header = headers.iter().find(|h|
            h.header_name().as_slice().to_ascii_lower() == "upgrade".to_string()
        );

        match header {
            Some(h) => {    if h.header_value().as_slice().to_ascii_lower() == "websocket".to_string()
                            {
                                flag = flag + 1
                            }
                       },
            None => {}
        }
    });
    if flag == 1
    {
       start_chan.send(response);
    }
}
<commit_msg>changes in the ws_loader.rs file to replace the progress_port of  the reponse with a new receiver and sending an appropriate message to the initial sender from the websocket.rs constructor<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use resource_task::{Done, LoadResponse, LoadData, start_sending};
use http_loader;
use http::headers::HeaderEnum;
use servo_util::task::spawn_named;
use std::ascii::AsciiExt;
use std::comm::{channel, Sender};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    spawn_named("ws_loader", proc() load(load_data, start_chan))
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {

    let(sen,rec)=channel();
    http_loader::load(load_data, sen);
    let mut response=rec.recv();
    let mut flag: int = 0;

    response.metadata.headers.as_ref().map(|headers| {
        let header = headers.iter().find(|h|
            h.header_name().as_slice().to_ascii_lower() == "upgrade".to_string()
        );
        match header {
            Some(h) => {    if h.header_value().as_slice().to_ascii_lower() == "websocket".to_string()
                            {
                                flag = flag + 1
                            }
                       },
            None => {}
        }
    });

    let(sen2, rec2) = channel();
    let response2 = rec2.recv();
    let progress_chan = start_sending(sen2, response2.metadata);
    response.progress_port = response2.progress_port;
    if flag == 1
    {
       start_chan.send(response);
       progress_chan.send(Done(Ok(())));
    }
    else
    {
       start_chan.send(response);
       progress_chan.send(Done(Err("invalid upgrade header value".to_string())));
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]

// Dependencies
mod vjoy_rust;

extern crate std;

use std::collections::HashMap;

trait IsVJoyDevice {
    fn get_vjoy_device_number(&self) -> u32;
}

trait HasAxes: IsVJoyDevice {
    // Values are HID constant - min - max triplets
    fn get_axis_map(&self) -> &HashMap<String, (u32, i64, i64)>;

    fn get_axis_hid(&self, name: &String) -> Option<u32> {
        match self.get_axis_map().get(name) {
            Some(&(hid, _, _)) => Some(hid),
            None => None
        }
    }

    fn get_axis_min(&self, name: &String) -> Option<i64> {
        match self.get_axis_map().get(name) {
            Some(&(_, min, _)) => Some(min),
            None => None
        }
    }

    fn get_axis_max(&self, name: &String) -> Option<i64> {
        match self.get_axis_map().get(name) {
            Some(&(_, _, max)) => Some(max),
            None => None
        }
    }

    fn get_axis_state(&self, name: &String) -> Option<i64>;

    //@todo change this to raw value, not percent
    fn set_axis_state(&self, name: &String, strength: f32) -> Result<(), &'static str> {
        let hid = self.get_axis_hid(name).unwrap();

        let mid: i64 = ((self.get_axis_max(name).unwrap() - self.get_axis_max(&name).unwrap())/2) as i64;
        let val = mid + (strength * (mid as f32)) as i64;

        match vjoy_rust::set_vjoystick_axis(self.get_vjoy_device_number(), hid, val) {
            Ok(_) => Ok(()),
            Err(_) => Err("Unable to set axis")
        }
    }
}

trait HasButtons: IsVJoyDevice {
    fn get_button_map(&self) -> &HashMap<String, u8>;

    fn get_button_index(&self, name: &String) -> Option<u8> {
        match self.get_button_map().get(name) {
            Some(index) => Some(*index),
            None => None
        }
    }

    fn get_button_state(&self, name: &String) -> Option<bool>;

    fn set_button_state(&self, name: &String, value: bool) -> Result<(), &'static str> {
        let index = self.get_button_index(name).unwrap();

        let valc = value as i32;

        match vjoy_rust::set_vjoystick_button(self.get_vjoy_device_number(), index, valc) {
            Ok(_) => Ok(()),
            Err(_) => Err("Unable to set virtual joystick button")
        }
    }
}

pub trait AcceptsInputs: HasAxes + HasButtons {
    fn set_input(&self, input: &Input) -> Result<(), &'static str> {
        match input.clone() {
            Input::Axis(name, strength) => self.set_axis_state(&name, strength),
            Input::Button(name, value) => self.set_button_state(&name, value)
        }
    }
}

//@todo track state
pub struct VN64C {
    axes: HashMap<String, (u32, i64, i64)>,
    buttons: HashMap<String, u8>,

    vjoy_device_number: u32
}

impl IsVJoyDevice for VN64C {
    fn get_vjoy_device_number(&self) -> u32 {
        return self.vjoy_device_number;
    }
}

impl HasAxes for VN64C {
    fn get_axis_map(&self) -> &HashMap<String, (u32, i64, i64)> {
        return &self.axes;
    }

    fn get_axis_state(&self, name: &String) -> Option<i64> {
        return Some(0); //@todo
    }
}

impl HasButtons for VN64C {
    fn get_button_map(&self) -> &HashMap<String, u8> {
        return &self.buttons;
    }

    fn get_button_state(&self, name: &String) -> Option<bool> {
        return Some(false);
    }
}

impl AcceptsInputs for VN64C {
}

impl VN64C {
    pub fn new(vjoy_device_number: u32) -> Result<Self, String> {
        let vjoy_device_number_native = vjoy_device_number;

        if vjoy_rust::is_vjoy_enabled() == false {
            return Err(format!("vJoy isn't enabled. Have you installed vJoy?"));
        }

        match verify_vjoystick_hardware(vjoy_device_number_native) {
            Ok(()) => (),
            Err(err) => return Err(format!("Virtual joystick {} can't act as an N64 controller: {}.\
                                            You may need to reconfigure your vJoy device",
                                           vjoy_device_number, err))
        }

        match vjoy_rust::claim_vjoystick(vjoy_device_number_native) {
            Err(msg) => return Err(format!("{}", msg)),
            _ => ()
        }

        match vjoy_rust::reset_vjoystick(vjoy_device_number_native) {
            Err(_) => return Err(format!("Unable to reset joystick")),
            _ => ()
        }

        let (axes, buttons) = match get_n64_controller_hardware(vjoy_device_number) {
            Ok((axes, buttons)) => (axes, buttons),
            Err(_) => return Err(format!("Getting N64 controller hardware failed"))
        };

        Ok( VN64C { axes: axes, buttons: buttons, vjoy_device_number: vjoy_device_number } )
    }
}

fn get_n64_controller_hardware(vjoy_device_number: u32) -> Result<(HashMap<String, (u32, i64, i64)>, HashMap<String, u8>), u8> {
    let mut axes = HashMap::new();

    let x_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x30) {
        Ok(min) => min,
        Err(msg) => return Err(1)
    };
    let x_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x30) {
        Ok(max) => max,
        Err(_) => return Err(2)
    };
    let y_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x31) {
        Ok(min) => min,
        Err(msg) => return Err(3)
    };
    let y_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x31) {
        Ok(max) => max,
        Err(_) => return Err(4)
    };

    axes.insert(String::from("x"), (0x30, x_min, x_max));
    axes.insert(String::from("y"), (0x31, y_min, y_max));

    let mut buttons = HashMap::new();
    buttons.insert(String::from("a"), 0x01);
    buttons.insert(String::from("b"), 0x02);
    buttons.insert(String::from("z"), 0x03);
    buttons.insert(String::from("l"), 0x04);
    buttons.insert(String::from("r"), 0x05);
    buttons.insert(String::from("start"), 0x06);
    buttons.insert(String::from("cup"), 0x07);
    buttons.insert(String::from("cdown"), 0x08);
    buttons.insert(String::from("cleft"), 0x09);
    buttons.insert(String::from("cright"), 0x0a);
    buttons.insert(String::from("dup"), 0x0b);
    buttons.insert(String::from("ddown"), 0x0c);
    buttons.insert(String::from("dleft"), 0x0d);
    buttons.insert(String::from("dright"), 0x0e);

    Ok((axes, buttons))
}

/*
fn get_gcn_controller_hardware() -> ControllerInputs {
    let mut axes = HashMap::new();
    axes.insert(String::from("jx"), 0x30); // USB HID: X
    axes.insert(String::from("jy"), 0x31); // USB HID: Y
    axes.insert(String::from("cx"), 0x33); // USB HID: Rx
    axes.insert(String::from("cy"), 0x34); // USB HID: Ry

    let mut buttons = HashMap::new();
    buttons.insert(String::from("a"), 0x01);
    buttons.insert(String::from("b"), 0x02);
    buttons.insert(String::from("x"), 0x03);
    buttons.insert(String::from("y"), 0x04);
    buttons.insert(String::from("z"), 0x05);
    buttons.insert(String::from("l"), 0x06);
    buttons.insert(String::from("r"), 0x07);
    buttons.insert(String::from("dup"), 0x08);
    buttons.insert(String::from("ddown"), 0x09);
    buttons.insert(String::from("dleft"), 0x0a);
    buttons.insert(String::from("dright"), 0x0b);

    ControllerInputs { axes: axes, buttons: buttons }
}
*/

#[derive(Clone)]
pub enum Input {
    Axis(String, f32),
    Button(String, bool)
}

//@todo implement
fn verify_vjoystick_hardware(index: u32) -> Result<(), String> {
    if vjoy_rust::get_vjoystick_axis_exists(index, 0x30)== false {
        return Err(format!("No X axis"));
    }

    if vjoy_rust::get_vjoystick_axis_exists(index, 0x31)== false {
        return Err(format!("No Y axis"));
    }

    if vjoy_rust::get_vjoystick_button_count(index) < 14 {
        return Err(format!("Less than {} buttons", 14));
    }

    Ok(())
}
<commit_msg>Add Gamecube controller to virtc<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]

// Dependencies
mod vjoy_rust;

extern crate std;

use std::collections::HashMap;

trait IsVJoyDevice {
    fn get_vjoy_device_number(&self) -> u32;

    // Err(1): vJoy isn't enabled
    // Err(2): Unable to claim vjoystick
    // Err(3): unable to reset vjoystick
    fn claim_and_reset(&self) -> Result<(), u8> {
        if vjoy_rust::is_vjoy_enabled() == false {
            return Err(1);
        }

        match vjoy_rust::claim_vjoystick(self.get_vjoy_device_number()) {
            Err(msg) => return Err(2),
            _ => ()
        }

        match vjoy_rust::reset_vjoystick(self.get_vjoy_device_number()) {
            Err(_) => return Err(3),
            _ => Ok(())
        }
    }
}

trait HasAxes: IsVJoyDevice {
    // Values are HID constant - min - max triplets
    fn get_axis_map(&self) -> &HashMap<String, (u32, i64, i64)>;

    fn get_axis_hid(&self, name: &String) -> Option<u32> {
        match self.get_axis_map().get(name) {
            Some(&(hid, _, _)) => Some(hid),
            None => None
        }
    }

    fn get_axis_min(&self, name: &String) -> Option<i64> {
        match self.get_axis_map().get(name) {
            Some(&(_, min, _)) => Some(min),
            None => None
        }
    }

    fn get_axis_max(&self, name: &String) -> Option<i64> {
        match self.get_axis_map().get(name) {
            Some(&(_, _, max)) => Some(max),
            None => None
        }
    }

    fn get_axis_state(&self, name: &String) -> Option<i64>;

    //@todo change this to raw value, not percent
    fn set_axis_state(&self, name: &String, strength: f32) -> Result<(), &'static str> {
        let hid = self.get_axis_hid(name).unwrap();

        let mid: i64 = ((self.get_axis_max(name).unwrap() - self.get_axis_max(&name).unwrap())/2) as i64;
        let val = mid + (strength * (mid as f32)) as i64;

        match vjoy_rust::set_vjoystick_axis(self.get_vjoy_device_number(), hid, val) {
            Ok(_) => Ok(()),
            Err(_) => Err("Unable to set axis")
        }
    }

    fn verify_vjoystick_axis_compatibility(&self) -> Result<(), ()> {
        for (_, &(axis_index, _, _)) in self.get_axis_map() {
            if vjoy_rust::get_vjoystick_axis_exists(self.get_vjoy_device_number(), axis_index)== false {
                return Err(());
            }
        }

        Ok(())
    }
}

trait HasButtons: IsVJoyDevice {
    fn get_button_map(&self) -> &HashMap<String, u8>;

    fn get_button_index(&self, name: &String) -> Option<u8> {
        match self.get_button_map().get(name) {
            Some(index) => Some(*index),
            None => None
        }
    }

    fn get_button_state(&self, name: &String) -> Option<bool>;

    fn set_button_state(&self, name: &String, value: bool) -> Result<(), &'static str> {
        let index = self.get_button_index(name).unwrap();

        let valc = value as i32;

        match vjoy_rust::set_vjoystick_button(self.get_vjoy_device_number(), index, valc) {
            Ok(_) => Ok(()),
            Err(_) => Err("Unable to set virtual joystick button")
        }
    }

    fn verify_vjoystick_button_compatibility(&self) -> Result<(), ()>
    {
        if (vjoy_rust::get_vjoystick_button_count(self.get_vjoy_device_number()) as usize) < self.get_button_map().len() {
            return Err(());
        }

        Ok(())
    }
}

trait HasAxesAndButtons: HasAxes + HasButtons {
    fn verify_vjoystick_compatibility(&self) -> Result<(), ()> {
        match self.verify_vjoystick_axis_compatibility() {
            Ok(_) => (),
            Err(_) => return Err(())
        }

        match self.verify_vjoystick_button_compatibility() {
            Ok(_) => Ok(()),
            Err(_) => Err(())
        }
    }
}

#[derive(Clone)]
pub enum Input {
    Axis(String, f32),
    Button(String, bool)
}
pub trait AcceptsInputs: HasAxesAndButtons {
    fn set_input(&self, input: &Input) -> Result<(), &'static str> {
        match input.clone() {
            Input::Axis(name, strength) => self.set_axis_state(&name, strength),
            Input::Button(name, value) => self.set_button_state(&name, value)
        }
    }
}

//@todo track state
pub struct VN64C {
    axes: HashMap<String, (u32, i64, i64)>,
    buttons: HashMap<String, u8>,
    vjoy_device_number: u32
}

impl IsVJoyDevice for VN64C {
    fn get_vjoy_device_number(&self) -> u32 {
        return self.vjoy_device_number;
    }
}

impl HasAxes for VN64C {
    fn get_axis_map(&self) -> &HashMap<String, (u32, i64, i64)> {
        return &self.axes;
    }

    fn get_axis_state(&self, name: &String) -> Option<i64> {
        return Some(0); //@todo
    }
}

impl HasButtons for VN64C {
    fn get_button_map(&self) -> &HashMap<String, u8> {
        return &self.buttons;
    }

    fn get_button_state(&self, name: &String) -> Option<bool> {
        return Some(false);
    }
}

impl HasAxesAndButtons for VN64C {}

impl AcceptsInputs for VN64C {}

impl VN64C {
    // Err(1): unable to get N64 hardware
    // Err(2): vjoystick doesn't meet N64 controller requirements
    // Err(3): unable to claim and reset vjoystick
    pub fn new(vjoy_device_number: u32) -> Result<Self, u8> {
        let (axes, buttons) = match get_n64_controller_hardware(vjoy_device_number) {
            Ok((axes, buttons)) => (axes, buttons),
            Err(_) => return Err(1)
        };

        let vn64c = VN64C { axes: axes, buttons: buttons, vjoy_device_number: vjoy_device_number };

        match vn64c.verify_vjoystick_compatibility() {
            Ok(_) => (),
            Err(_) => return Err(2)
        }

        match vn64c.claim_and_reset() {
            Ok(_) => Ok(vn64c),
            Err(_) => Err(3)
        }
    }
}

fn get_n64_controller_hardware(vjoy_device_number: u32) -> Result<(HashMap<String, (u32, i64, i64)>, HashMap<String, u8>), u8> {
    let mut axes = HashMap::new();

    let x_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x30) {
        Ok(min) => min,
        Err(msg) => return Err(1)
    };
    let x_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x30) {
        Ok(max) => max,
        Err(_) => return Err(2)
    };
    let y_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x31) {
        Ok(min) => min,
        Err(msg) => return Err(3)
    };
    let y_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x31) {
        Ok(max) => max,
        Err(_) => return Err(4)
    };

    axes.insert(String::from("x"), (0x30, x_min, x_max));
    axes.insert(String::from("y"), (0x31, y_min, y_max));

    let mut buttons = HashMap::new();
    buttons.insert(String::from("a"), 0x01);
    buttons.insert(String::from("b"), 0x02);
    buttons.insert(String::from("z"), 0x03);
    buttons.insert(String::from("l"), 0x04);
    buttons.insert(String::from("r"), 0x05);
    buttons.insert(String::from("start"), 0x06);
    buttons.insert(String::from("cup"), 0x07);
    buttons.insert(String::from("cdown"), 0x08);
    buttons.insert(String::from("cleft"), 0x09);
    buttons.insert(String::from("cright"), 0x0a);
    buttons.insert(String::from("dup"), 0x0b);
    buttons.insert(String::from("ddown"), 0x0c);
    buttons.insert(String::from("dleft"), 0x0d);
    buttons.insert(String::from("dright"), 0x0e);

    Ok((axes, buttons))
}

//@todo track state
pub struct VGCNC {
    axes: HashMap<String, (u32, i64, i64)>,
    buttons: HashMap<String, u8>,
    vjoy_device_number: u32
}

impl IsVJoyDevice for VGCNC {
    fn get_vjoy_device_number(&self) -> u32 {
        return self.vjoy_device_number;
    }
}

impl HasAxes for VGCNC {
    fn get_axis_map(&self) -> &HashMap<String, (u32, i64, i64)> {
        return &self.axes;
    }

    fn get_axis_state(&self, name: &String) -> Option<i64> {
        return Some(0); //@todo
    }
}

impl HasButtons for VGCNC {
    fn get_button_map(&self) -> &HashMap<String, u8> {
        return &self.buttons;
    }

    fn get_button_state(&self, name: &String) -> Option<bool> {
        return Some(false);
    }
}

impl HasAxesAndButtons for VGCNC {}

impl AcceptsInputs for VGCNC {}

impl VGCNC {
    // Err(1): unable to get GCN hardware
    // Err(2): vjoystick doesn't meet GCN controller requirements
    // Err(3): unable to claim and reset vjoystick
    pub fn new(vjoy_device_number: u32) -> Result<Self, u8> {
        let (axes, buttons) = match get_gcn_controller_hardware(vjoy_device_number) {
            Ok((axes, buttons)) => (axes, buttons),
            Err(_) => return Err(1)
        };

        let vgcnc = VGCNC { axes: axes, buttons: buttons, vjoy_device_number: vjoy_device_number };

        match vgcnc.verify_vjoystick_compatibility() {
            Ok(_) => (),
            Err(_) => return Err(2)
        }

        match vgcnc.claim_and_reset() {
            Ok(_) => Ok(vgcnc),
            Err(_) => Err(3)
        }
    }
}

fn get_gcn_controller_hardware(vjoy_device_number: u32)
        -> Result<(HashMap<String, (u32, i64, i64)>, HashMap<String, u8>), u8>
{
    let mut axes = HashMap::new();

    let jx_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x30) {
        Ok(min) => min,
        Err(msg) => return Err(1)
    };
    let jx_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x30) {
        Ok(max) => max,
        Err(_) => return Err(2)
    };
    let jy_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x31) {
        Ok(min) => min,
        Err(msg) => return Err(3)
    };
    let jy_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x31) {
        Ok(max) => max,
        Err(_) => return Err(4)
    };

    let cx_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x33) {
        Ok(min) => min,
        Err(msg) => return Err(1)
    };
    let cx_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x33) {
        Ok(max) => max,
        Err(_) => return Err(2)
    };
    let cy_min = match vjoy_rust::get_vjoystick_axis_min(vjoy_device_number, 0x34) {
        Ok(min) => min,
        Err(msg) => return Err(3)
    };
    let cy_max = match vjoy_rust::get_vjoystick_axis_max(vjoy_device_number, 0x34) {
        Ok(max) => max,
        Err(_) => return Err(4)
    };

    axes.insert(String::from("jx"), (0x30, jx_min, jx_max));
    axes.insert(String::from("jy"), (0x31, jy_min, jy_max));
    axes.insert(String::from("cx"), (0x33, cx_min, cx_max));
    axes.insert(String::from("cy"), (0x34, cy_min, cy_max));

    let mut buttons = HashMap::new();
    buttons.insert(String::from("a"), 0x01);
    buttons.insert(String::from("b"), 0x02);
    buttons.insert(String::from("x"), 0x03);
    buttons.insert(String::from("y"), 0x04);
    buttons.insert(String::from("z"), 0x05);
    buttons.insert(String::from("l"), 0x06);
    buttons.insert(String::from("r"), 0x07);
    buttons.insert(String::from("dup"), 0x08);
    buttons.insert(String::from("ddown"), 0x09);
    buttons.insert(String::from("dleft"), 0x0a);
    buttons.insert(String::from("dright"), 0x0b);

    Ok((axes, buttons))
}<|endoftext|>


<commit_before>//! Main interface for a stream of events the Supervisor can send out
//! in the course of its operations.
//!
//! Currently, the Supervisor is able to send events to a [NATS
//! Streaming][1] server. The `init_stream` function must be called
//! before sending events to initialize the publishing thread in the
//! background. Thereafter, you can pass "event" structs to the
//! `event` function, which will publish the event to the stream.
//!
//! All events are published under the "habitat" subject.
//!
//! [1]:https://github.com/nats-io/nats-streaming-server

mod error;

#[cfg(feature = "nitox_stream")]
#[path = "event/nitox.rs"]
mod stream_impl;

// This is the default, but setting it as a default in Cargo.toml
// makes it trickier to use nitox instead.
#[cfg(any(feature = "ratsio_stream", not(feature = "nitox_stream")))]
#[path = "event/ratsio.rs"]
mod stream_impl;
mod types;

pub(crate) use self::types::ServiceMetadata;
use self::types::{EventMessage,
                  EventMetadata,
                  HealthCheckEvent,
                  ServiceStartedEvent,
                  ServiceStoppedEvent};
use crate::{error::Result as SupResult,
            manager::{service::{HealthCheckResult,
                                Service},
                      sys::Sys}};
use clap::ArgMatches;
pub use error::{Error,
                Result};
use futures::sync::mpsc::UnboundedSender;
use habitat_common::types::{AutomateAuthToken,
                            EventStreamMetadata};
use habitat_core::env::Config as EnvConfig;
use state::Container;
use std::{net::SocketAddr,
          num::ParseIntError,
          str::FromStr,
          sync::Once,
          time::Duration};

static INIT: Once = Once::new();
lazy_static! {
    // TODO (CM): When const fn support lands in stable, we can ditch
    // this lazy_static call.

    /// Reference to the event stream.
    static ref EVENT_STREAM: Container = Container::new();
    /// Core information that is shared between all events.
    static ref EVENT_CORE: Container = Container::new();
}

/// Starts a new thread for sending events to a NATS Streaming
/// server. Stashes the handle to the stream, as well as the core
/// event information that will be a part of all events, in a global
/// static reference for access later.
pub fn init_stream(config: EventStreamConfig, event_core: EventCore) -> Result<()> {
    // call_once can't return a Result (or anything), so we'll fake it
    // by hanging onto any error we might receive.
    let mut return_value: Result<()> = Ok(());

    INIT.call_once(|| {
            let conn_info = EventConnectionInfo::new(config.token, config.url);
            match stream_impl::init_stream(conn_info) {
                Ok(event_stream) => {
                    EVENT_STREAM.set(event_stream);
                    EVENT_CORE.set(event_core);
                }
                Err(e) => return_value = Err(e),
            }
        });

    return_value
}

/// Captures all event stream-related configuration options that would
/// be passed in by a user
#[derive(Clone, Debug)]
pub struct EventStreamConfig {
    environment: String,
    application: String,
    meta:        EventStreamMetadata,
    token:       AutomateAuthToken,
    url:         String,
}

impl EventStreamConfig {
    /// Create an instance from Clap arguments.
    // TODO (CM): result type!
    pub fn from_matches(m: &ArgMatches) -> SupResult<EventStreamConfig> {
        Ok(EventStreamConfig { environment: m.value_of("EVENT_STREAM_ENVIRONMENT")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               application: m.value_of("EVENT_STREAM_APPLICATION")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               meta:        EventStreamMetadata::from(m),
                               token:       AutomateAuthToken::from(m),
                               url:         m.value_of("EVENT_STREAM_URL")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"), })
    }
}

/// All the information needed to establish a connection to a NATS
/// Streaming server.
// TODO: This will change as we firm up what the interaction between
// Habitat and A2 looks like.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
    pub auth_token:  AutomateAuthToken,
}

impl EventConnectionInfo {
    pub fn new(auth_token: AutomateAuthToken, cluster_uri: String) -> Self {
        EventConnectionInfo { name: "hab_client".to_string(),
                              verbose: true,
                              cluster_uri,
                              cluster_id: "event-service".to_string(),
                              auth_token }
    }
}

/// A collection of data that will be present in all events. Rather
/// than baking this into the structure of each event, we represent it
/// once and merge the information into the final rendered form of the
/// event.
///
/// This prevents us from having to thread information throughout the
/// system, just to get it to the places where the events are
/// generated (e.g., not all code has direct access to the
/// Supervisor's ID).
#[derive(Clone, Debug)]
pub struct EventCore {
    /// The unique identifier of the Supervisor sending the event.
    supervisor_id: String,
    ip_address: SocketAddr,
    // TODO (CM): could add application and environment to the meta
    // map directly... hrmm
    application: String,
    environment: String,
    meta:        EventStreamMetadata,
}

impl EventCore {
    pub fn new(config: &EventStreamConfig, sys: &Sys) -> Self {
        EventCore { supervisor_id: sys.member_id.clone(),
                    ip_address:    sys.gossip_listen(),
                    environment:   config.environment.clone(),
                    application:   config.application.clone(),
                    meta:          config.meta.clone(), }
    }
}

/// Send an event for the start of a Service.
pub fn service_started(service: &Service) {
    if stream_initialized() {
        publish(ServiceStartedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

/// Send an event for the stop of a Service.
pub fn service_stopped(service: &Service) {
    if stream_initialized() {
        publish(ServiceStoppedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

// Takes metadata directly, rather than a `&Service` like other event
// functions, because of how the asynchronous health checking
// currently works. Revisit when async/await + Pin is all stabilized.
pub fn health_check(metadata: ServiceMetadata,
                    check_result: HealthCheckResult,
                    duration: Option<Duration>) {
    if stream_initialized() {
        publish(HealthCheckEvent { service_metadata: Some(metadata),
                                   event_metadata:   None,
                                   result:           Into::<types::HealthCheck>::into(check_result)
                                                     as i32,
                                   duration:         duration.map(Duration::into), });
    }
}

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

/// Internal helper function to know whether or not to go to the trouble of
/// creating event structures. If the event stream hasn't been
/// initialized, then we shouldn't need to do anything.
fn stream_initialized() -> bool { EVENT_STREAM.try_get::<EventStream>().is_some() }

/// Publish an event. This is the main interface that client code will
/// use.
///
/// If `init_stream` has not been called already, this function will
/// be a no-op.
fn publish(mut event: impl EventMessage) {
    if let Some(e) = EVENT_STREAM.try_get::<EventStream>() {
        // TODO (CM): Yeah... this is looking pretty gross. The
        // intention is to be able to timestamp the events right as
        // they go out.
        //
        // We *could* set the time when we convert the EventCore to a
        // EventMetadata struct, but that seems odd.
        //
        // It probably means that this structure just isn't the right
        // one.
        //
        // The ugliness is at least contained, though.
        event.event_metadata(EventMetadata { timestamp:
                                                 Some(std::time::SystemTime::now().into()),
                                             ..EVENT_CORE.get::<EventCore>().to_event_metadata() });

        e.send(event.to_bytes());
    }
}

/// A lightweight handle for the event stream. All events get to the
/// event stream through this.
struct EventStream(UnboundedSender<Vec<u8>>);

impl EventStream {
    /// Queues an event to be sent out.
    fn send(&self, event: Vec<u8>) {
        trace!("About to queue an event: {:?}", event);
        if let Err(e) = self.0.unbounded_send(event) {
            error!("Failed to queue event: {:?}", e);
        }
    }
}

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

/// How long should we for the event thread to start up before
/// abandoning it and shutting down?
#[derive(Clone, Debug)]
struct EventThreadStartupWait(u64);

impl Default for EventThreadStartupWait {
    fn default() -> Self { Self(5) }
}

impl FromStr for EventThreadStartupWait {
    type Err = ParseIntError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { Ok(Self(s.parse()?)) }
}

impl EnvConfig for EventThreadStartupWait {
    const ENVVAR: &'static str = "HAB_EVENT_THREAD_STARTUP_WAIT_SEC";
}

impl Into<Duration> for EventThreadStartupWait {
    fn into(self) -> Duration { Duration::from_secs(self.0) }
}
<commit_msg>[PR Feedback] Remove unnecessary i32 cast<commit_after>//! Main interface for a stream of events the Supervisor can send out
//! in the course of its operations.
//!
//! Currently, the Supervisor is able to send events to a [NATS
//! Streaming][1] server. The `init_stream` function must be called
//! before sending events to initialize the publishing thread in the
//! background. Thereafter, you can pass "event" structs to the
//! `event` function, which will publish the event to the stream.
//!
//! All events are published under the "habitat" subject.
//!
//! [1]:https://github.com/nats-io/nats-streaming-server

mod error;

#[cfg(feature = "nitox_stream")]
#[path = "event/nitox.rs"]
mod stream_impl;

// This is the default, but setting it as a default in Cargo.toml
// makes it trickier to use nitox instead.
#[cfg(any(feature = "ratsio_stream", not(feature = "nitox_stream")))]
#[path = "event/ratsio.rs"]
mod stream_impl;
mod types;

pub(crate) use self::types::ServiceMetadata;
use self::types::{EventMessage,
                  EventMetadata,
                  HealthCheckEvent,
                  ServiceStartedEvent,
                  ServiceStoppedEvent};
use crate::{error::Result as SupResult,
            manager::{service::{HealthCheckResult,
                                Service},
                      sys::Sys}};
use clap::ArgMatches;
pub use error::{Error,
                Result};
use futures::sync::mpsc::UnboundedSender;
use habitat_common::types::{AutomateAuthToken,
                            EventStreamMetadata};
use habitat_core::env::Config as EnvConfig;
use state::Container;
use std::{net::SocketAddr,
          num::ParseIntError,
          str::FromStr,
          sync::Once,
          time::Duration};

static INIT: Once = Once::new();
lazy_static! {
    // TODO (CM): When const fn support lands in stable, we can ditch
    // this lazy_static call.

    /// Reference to the event stream.
    static ref EVENT_STREAM: Container = Container::new();
    /// Core information that is shared between all events.
    static ref EVENT_CORE: Container = Container::new();
}

/// Starts a new thread for sending events to a NATS Streaming
/// server. Stashes the handle to the stream, as well as the core
/// event information that will be a part of all events, in a global
/// static reference for access later.
pub fn init_stream(config: EventStreamConfig, event_core: EventCore) -> Result<()> {
    // call_once can't return a Result (or anything), so we'll fake it
    // by hanging onto any error we might receive.
    let mut return_value: Result<()> = Ok(());

    INIT.call_once(|| {
            let conn_info = EventConnectionInfo::new(config.token, config.url);
            match stream_impl::init_stream(conn_info) {
                Ok(event_stream) => {
                    EVENT_STREAM.set(event_stream);
                    EVENT_CORE.set(event_core);
                }
                Err(e) => return_value = Err(e),
            }
        });

    return_value
}

/// Captures all event stream-related configuration options that would
/// be passed in by a user
#[derive(Clone, Debug)]
pub struct EventStreamConfig {
    environment: String,
    application: String,
    meta:        EventStreamMetadata,
    token:       AutomateAuthToken,
    url:         String,
}

impl EventStreamConfig {
    /// Create an instance from Clap arguments.
    // TODO (CM): result type!
    pub fn from_matches(m: &ArgMatches) -> SupResult<EventStreamConfig> {
        Ok(EventStreamConfig { environment: m.value_of("EVENT_STREAM_ENVIRONMENT")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               application: m.value_of("EVENT_STREAM_APPLICATION")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"),
                               meta:        EventStreamMetadata::from(m),
                               token:       AutomateAuthToken::from(m),
                               url:         m.value_of("EVENT_STREAM_URL")
                                             .map(str::to_string)
                                             .expect("Required option for EventStream feature"), })
    }
}

/// All the information needed to establish a connection to a NATS
/// Streaming server.
// TODO: This will change as we firm up what the interaction between
// Habitat and A2 looks like.
pub struct EventConnectionInfo {
    pub name:        String,
    pub verbose:     bool,
    pub cluster_uri: String,
    pub cluster_id:  String,
    pub auth_token:  AutomateAuthToken,
}

impl EventConnectionInfo {
    pub fn new(auth_token: AutomateAuthToken, cluster_uri: String) -> Self {
        EventConnectionInfo { name: "hab_client".to_string(),
                              verbose: true,
                              cluster_uri,
                              cluster_id: "event-service".to_string(),
                              auth_token }
    }
}

/// A collection of data that will be present in all events. Rather
/// than baking this into the structure of each event, we represent it
/// once and merge the information into the final rendered form of the
/// event.
///
/// This prevents us from having to thread information throughout the
/// system, just to get it to the places where the events are
/// generated (e.g., not all code has direct access to the
/// Supervisor's ID).
#[derive(Clone, Debug)]
pub struct EventCore {
    /// The unique identifier of the Supervisor sending the event.
    supervisor_id: String,
    ip_address: SocketAddr,
    // TODO (CM): could add application and environment to the meta
    // map directly... hrmm
    application: String,
    environment: String,
    meta:        EventStreamMetadata,
}

impl EventCore {
    pub fn new(config: &EventStreamConfig, sys: &Sys) -> Self {
        EventCore { supervisor_id: sys.member_id.clone(),
                    ip_address:    sys.gossip_listen(),
                    environment:   config.environment.clone(),
                    application:   config.application.clone(),
                    meta:          config.meta.clone(), }
    }
}

/// Send an event for the start of a Service.
pub fn service_started(service: &Service) {
    if stream_initialized() {
        publish(ServiceStartedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

/// Send an event for the stop of a Service.
pub fn service_stopped(service: &Service) {
    if stream_initialized() {
        publish(ServiceStoppedEvent { service_metadata: Some(service.to_service_metadata()),
                                      event_metadata:   None, });
    }
}

// Takes metadata directly, rather than a `&Service` like other event
// functions, because of how the asynchronous health checking
// currently works. Revisit when async/await + Pin is all stabilized.
pub fn health_check(metadata: ServiceMetadata,
                    check_result: HealthCheckResult,
                    duration: Option<Duration>) {
    if stream_initialized() {
        let check_result: types::HealthCheck = check_result.into();
        publish(HealthCheckEvent { service_metadata: Some(metadata),
                                   event_metadata:   None,
                                   result:           i32::from(check_result),
                                   duration:         duration.map(Duration::into), });
    }
}

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

/// Internal helper function to know whether or not to go to the trouble of
/// creating event structures. If the event stream hasn't been
/// initialized, then we shouldn't need to do anything.
fn stream_initialized() -> bool { EVENT_STREAM.try_get::<EventStream>().is_some() }

/// Publish an event. This is the main interface that client code will
/// use.
///
/// If `init_stream` has not been called already, this function will
/// be a no-op.
fn publish(mut event: impl EventMessage) {
    if let Some(e) = EVENT_STREAM.try_get::<EventStream>() {
        // TODO (CM): Yeah... this is looking pretty gross. The
        // intention is to be able to timestamp the events right as
        // they go out.
        //
        // We *could* set the time when we convert the EventCore to a
        // EventMetadata struct, but that seems odd.
        //
        // It probably means that this structure just isn't the right
        // one.
        //
        // The ugliness is at least contained, though.
        event.event_metadata(EventMetadata { timestamp:
                                                 Some(std::time::SystemTime::now().into()),
                                             ..EVENT_CORE.get::<EventCore>().to_event_metadata() });

        e.send(event.to_bytes());
    }
}

/// A lightweight handle for the event stream. All events get to the
/// event stream through this.
struct EventStream(UnboundedSender<Vec<u8>>);

impl EventStream {
    /// Queues an event to be sent out.
    fn send(&self, event: Vec<u8>) {
        trace!("About to queue an event: {:?}", event);
        if let Err(e) = self.0.unbounded_send(event) {
            error!("Failed to queue event: {:?}", e);
        }
    }
}

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

/// How long should we for the event thread to start up before
/// abandoning it and shutting down?
#[derive(Clone, Debug)]
struct EventThreadStartupWait(u64);

impl Default for EventThreadStartupWait {
    fn default() -> Self { Self(5) }
}

impl FromStr for EventThreadStartupWait {
    type Err = ParseIntError;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> { Ok(Self(s.parse()?)) }
}

impl EnvConfig for EventThreadStartupWait {
    const ENVVAR: &'static str = "HAB_EVENT_THREAD_STARTUP_WAIT_SEC";
}

impl Into<Duration> for EventThreadStartupWait {
    fn into(self) -> Duration { Duration::from_secs(self.0) }
}
<|endoftext|>


<commit_before>//! Control agents module.

use super::Agent;
use domains::Transition;
use policies::Policy;

pub trait Controller<S, A>: Agent<Sample = Transition<S, A>> {
    /// Sample the target policy for a given state `s`.
    fn pi(&mut self, s: &S) -> usize;

    /// Sample the behaviour policy for a given state `s`.
    fn mu(&mut self, s: &S) -> usize;

    /// Sample a given policy against some state `s` for this agent.
    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S) -> usize;
}

pub mod td;
pub mod gtd;
pub mod totd;
pub mod actor_critic;
<commit_msg>refactor(agents): change output type in `Controller` trait<commit_after>//! Control agents module.

use super::Agent;
use domains::Transition;
use policies::Policy;

pub trait Controller<S, A>: Agent<Sample = Transition<S, A>> {
    /// Sample the target policy for a given state `s`.
    fn pi(&mut self, s: &S) -> A;

    /// Sample the behaviour policy for a given state `s`.
    fn mu(&mut self, s: &S) -> A;

    /// Sample a given policy against some state `s` for this agent.
    fn evaluate_policy<T: Policy>(&self, p: &mut T, s: &S) -> A;
}

pub mod td;
pub mod gtd;
pub mod totd;
pub mod actor_critic;
<|endoftext|>


<commit_before>#![allow(dead_code)]

use scaii_defs::protos;
use scaii_defs::{Module, Recorder};
use scaii_defs::protos::{MultiMessage, RecorderStep, ScaiiPacket};
use scaii_defs::protos::scaii_packet::SpecificMsg;
use std::error::Error;
use std::fmt;
use std::path::PathBuf;
use std::fs;

use bincode::{serialize, Infinite};
use std::io::prelude::*;
use std::fs::File;
use prost::Message;
use util;

#[cfg(test)]
mod test;

#[derive(Debug)]
struct RecorderError {
    details: String,
}

impl RecorderError {
    fn new(msg: &str) -> RecorderError {
        RecorderError { details: msg.to_string() }
    }
}

impl fmt::Display for RecorderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for RecorderError {
    fn description(&self) -> &str {
        &self.details
    }
}

//
// wrapper structs for serialized proto messages
//

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosSerializationResponse {
    pub data: Vec<u8>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosAction {
    pub data: Vec<u8>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosScaiiPacket {
    pub data: Vec<u8>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosEndpoint {
    pub data: Vec<u8>,
}

//
//  structs supporting ReplayAction
//

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum GameAction {
    DecisionPoint(SerializedProtosAction),
    Step,
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum ReplayAction {
    Header(ReplayHeader),
    Delta(GameAction),
    Keyframe(SerializationInfo, GameAction),
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializationInfo {
    pub source: SerializedProtosEndpoint,
    pub data: SerializedProtosSerializationResponse,
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct ReplayHeader {
    pub configs: SerializedProtosScaiiPacket,
}

//
// RecorderManager manages recording
//

pub struct RecorderManager {
    staged_ser_info: Option<SerializationInfo>,
    file_path: Option<PathBuf>,
    replay: Vec<ReplayAction>,
    is_recording: bool,
    writable_file: Option<File>,
}
impl RecorderManager {
    pub fn new() -> Self {
        RecorderManager {
            staged_ser_info: None,
            file_path: None,
            replay: Vec::new(),
            is_recording: false,
            writable_file: None,
        }
    }

    fn init(&mut self) -> Result<(), Box<Error>> {
        let replay_dir_path_buf = get_default_replay_dir()?;
        ensure_dir_exists(&replay_dir_path_buf)?;
        let path_buf = get_default_replay_file_path()?;
        self.file_path = Some(path_buf);
        Ok(())
    }

    fn get_serialized_protos_action(
        &mut self,
        action: &protos::Action,
    ) -> Result<SerializedProtosAction, Box<Error>> {
        let mut action_data: Vec<u8> = Vec::new();
        action.encode(&mut action_data)?;
        Ok(SerializedProtosAction { data: action_data })
    }

    fn get_serialized_protos_serialization_response(
        &mut self,
        ser_resp: &protos::SerializationResponse,
    ) -> Result<SerializedProtosSerializationResponse, Box<Error>> {
        let mut ser_resp_data: Vec<u8> = Vec::new();
        ser_resp.encode(&mut ser_resp_data)?;
        Ok(SerializedProtosSerializationResponse {
            data: ser_resp_data,
        })
    }

    fn get_serialized_protos_endpoint(
        &mut self,
        endpoint: &protos::Endpoint,
    ) -> Result<SerializedProtosEndpoint, Box<Error>> {
        let mut endpoint_data: Vec<u8> = Vec::new();
        endpoint.encode(&mut endpoint_data)?;
        Ok(SerializedProtosEndpoint { data: endpoint_data })
    }

    fn get_serialized_protos_scaii_packet(
        &mut self,
        pkt: &protos::ScaiiPacket,
    ) -> Result<SerializedProtosScaiiPacket, Box<Error>> {
        let mut pkt_data: Vec<u8> = Vec::new();
        pkt.encode(&mut pkt_data)?;
        Ok(SerializedProtosScaiiPacket { data: pkt_data })
    }

    fn handle_pkt(&mut self, pkt: &ScaiiPacket) -> Result<(), Box<Error>> {
        let src_endpoint = &pkt.src;
        let ser_protos_src_endpoint = self.get_serialized_protos_endpoint(src_endpoint)?;
        let specific_msg = &pkt.specific_msg;
        match *specific_msg {
            Some(SpecificMsg::RecorderConfig(_)) => {
                self.is_recording = true;
                let ser_protos_scaii_pkt = self.get_serialized_protos_scaii_packet(pkt)?;
                let replay_header = ReplayHeader { configs: ser_protos_scaii_pkt };
                let replay_action = ReplayAction::Header(replay_header);
                self.start_recording(&replay_action)?;
            }
            Some(SpecificMsg::SerResp(ref ser_resp)) => {
                if self.is_recording {
                    let ser_protos_ser_resp =
                        self.get_serialized_protos_serialization_response(ser_resp)?;
                    let ser_info = SerializationInfo {
                        source: ser_protos_src_endpoint,
                        data: ser_protos_ser_resp,
                    };
                    if let Some(SerializationInfo { .. }) = self.staged_ser_info {
                        return Err(Box::new(RecorderError::new(
                            "Received consecutive SerializationInfo packets - expected RecorderStep in between.",
                        )));
                    }
                    self.staged_ser_info = Some(ser_info);
                }
            }
            Some(SpecificMsg::RecorderStep(ref rec_step)) => {
                if self.is_recording {
                    if let Some(SerializationInfo { .. }) = self.staged_ser_info {
                        self.save_keyframe(rec_step)?;
                    } else {
                        let game_action = self.get_game_action_for_protos_action(rec_step)?;
                        let replay_action = ReplayAction::Delta(game_action);
                        self.persist_replay_action(&replay_action)?;
                    }
                }
            }
            Some(SpecificMsg::GameComplete(_)) => {
                self.stop_recording();
            }
            _ => {}
        }
        Ok(())
    }

    fn stop_recording(&mut self) {
        self.writable_file = None;
    }

    fn start_recording(&mut self, header_replay_action: &ReplayAction) -> Result<(), Box<Error>> {
        println!("recording header.");
        if self.file_path == None {
            return Err(Box::new(RecorderError::new(
                "RecorderManager.file_path not specified prior to start of recording.",
            )));
        }
        let path = self.file_path.clone().unwrap();
        let f = File::create(&path).expect("could not write to replay file");
        self.writable_file = Some(f);
        self.persist_replay_action(header_replay_action)?;
        Ok(())
    }

    fn persist_replay_action(&mut self, replay_action: &ReplayAction) -> Result<(), Box<Error>> {
        println!("persisting replayAction {:?}", replay_action);
        match self.writable_file {
            None => {
                return Err(Box::new(RecorderError::new(
                    "RecorderManager.writable_file not open for recording replay action.",
                )));
            }
            Some(ref mut file) => {
                let encoded: Vec<u8> = serialize(replay_action, Infinite).unwrap();
                let data_size = encoded.len();
                let write_result = file.write(&encoded);
                if write_result.unwrap() != data_size {
                    return Err(Box::new(RecorderError::new(
                        "could not write entire replay_action to replay file.",
                    )));
                }
            }
        }
        Ok(())
    }

    fn get_game_action_for_protos_action(
        &mut self,
        rec_step: &RecorderStep,
    ) -> Result<GameAction, Box<Error>> {
        if rec_step.is_decision_point {
            if rec_step.action == None {
                return Err(Box::new(RecorderError::new(
                    "Malformed RecordStep: no action present but is_decision_point was true.",
                )));
            }
            let serialized_protos_action = self.get_serialized_protos_action(
                &rec_step.action.clone().unwrap(),
            )?;
            Ok(GameAction::DecisionPoint(serialized_protos_action))
        } else {
            Ok(GameAction::Step)
        }
    }

    fn save_keyframe(&mut self, rec_step: &RecorderStep) -> Result<(), Box<Error>> {
        if rec_step.action == None {
            return Err(Box::new(RecorderError::new(
                "Cannot create keyFrame to store - action missing.",
            )));
        }
        let game_action = self.get_game_action_for_protos_action(rec_step)?;
        let ser_info = self.staged_ser_info.clone();
        if ser_info == None {
            return Err(Box::new(RecorderError::new(
                "Cannot create keyFrame to store - ser_info missing.",
            )));
        }
        let replay_action = ReplayAction::Keyframe(ser_info.clone().unwrap(), game_action);
        self.persist_replay_action(&replay_action)?;
        self.staged_ser_info = None;
        Ok(())
    }
}

impl Module for RecorderManager {
    fn process_msg(&mut self, msg: &ScaiiPacket) -> Result<(), Box<Error>> {
        println!("recorderManager handling packet");
        self.handle_pkt(msg)
    }

    /// return empty messages
    fn get_messages(&mut self) -> MultiMessage {
        let pkts: Vec<ScaiiPacket> = Vec::new();
        MultiMessage { packets: pkts }
    }
}

impl Recorder for RecorderManager {}

pub fn get_default_replay_file_path() -> Result<PathBuf, Box<Error>> {
    let mut replay_dir_path_buf = get_default_replay_dir()?;
    replay_dir_path_buf.push("replay_data.txt");
    Ok(replay_dir_path_buf)
}

pub fn get_default_replay_dir() -> Result<PathBuf, Box<Error>> {
    let mut scaii_root = util::get_scaii_root()?;
    scaii_root.push("core");
    scaii_root.push("replay_data");
    Ok(scaii_root)
}

fn ensure_dir_exists(path_buf: &PathBuf) -> Result<(), Box<Error>> {
    if !path_buf.as_path().exists() {
        fs::create_dir_all(path_buf.as_path())?;
    }
    Ok(())
}
<commit_msg>change replay file to have .sky file extension<commit_after>#![allow(dead_code)]

use scaii_defs::protos;
use scaii_defs::{Module, Recorder};
use scaii_defs::protos::{MultiMessage, RecorderStep, ScaiiPacket};
use scaii_defs::protos::scaii_packet::SpecificMsg;
use std::error::Error;
use std::fmt;
use std::path::PathBuf;
use std::fs;

use bincode::{serialize, Infinite};
use std::io::prelude::*;
use std::fs::File;
use prost::Message;
use util;

#[cfg(test)]
mod test;

#[derive(Debug)]
struct RecorderError {
    details: String,
}

impl RecorderError {
    fn new(msg: &str) -> RecorderError {
        RecorderError { details: msg.to_string() }
    }
}

impl fmt::Display for RecorderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.details)
    }
}

impl Error for RecorderError {
    fn description(&self) -> &str {
        &self.details
    }
}

//
// wrapper structs for serialized proto messages
//

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosSerializationResponse {
    pub data: Vec<u8>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosAction {
    pub data: Vec<u8>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosScaiiPacket {
    pub data: Vec<u8>,
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializedProtosEndpoint {
    pub data: Vec<u8>,
}

//
//  structs supporting ReplayAction
//

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum GameAction {
    DecisionPoint(SerializedProtosAction),
    Step,
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub enum ReplayAction {
    Header(ReplayHeader),
    Delta(GameAction),
    Keyframe(SerializationInfo, GameAction),
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct SerializationInfo {
    pub source: SerializedProtosEndpoint,
    pub data: SerializedProtosSerializationResponse,
}

#[derive(Clone, Serialize, Deserialize, PartialEq, Debug)]
pub struct ReplayHeader {
    pub configs: SerializedProtosScaiiPacket,
}

//
// RecorderManager manages recording
//

pub struct RecorderManager {
    staged_ser_info: Option<SerializationInfo>,
    file_path: Option<PathBuf>,
    replay: Vec<ReplayAction>,
    is_recording: bool,
    writable_file: Option<File>,
}
impl RecorderManager {
    pub fn new() -> Self {
        RecorderManager {
            staged_ser_info: None,
            file_path: None,
            replay: Vec::new(),
            is_recording: false,
            writable_file: None,
        }
    }

    fn init(&mut self) -> Result<(), Box<Error>> {
        let replay_dir_path_buf = get_default_replay_dir()?;
        ensure_dir_exists(&replay_dir_path_buf)?;
        let path_buf = get_default_replay_file_path()?;
        self.file_path = Some(path_buf);
        Ok(())
    }

    fn get_serialized_protos_action(
        &mut self,
        action: &protos::Action,
    ) -> Result<SerializedProtosAction, Box<Error>> {
        let mut action_data: Vec<u8> = Vec::new();
        action.encode(&mut action_data)?;
        Ok(SerializedProtosAction { data: action_data })
    }

    fn get_serialized_protos_serialization_response(
        &mut self,
        ser_resp: &protos::SerializationResponse,
    ) -> Result<SerializedProtosSerializationResponse, Box<Error>> {
        let mut ser_resp_data: Vec<u8> = Vec::new();
        ser_resp.encode(&mut ser_resp_data)?;
        Ok(SerializedProtosSerializationResponse {
            data: ser_resp_data,
        })
    }

    fn get_serialized_protos_endpoint(
        &mut self,
        endpoint: &protos::Endpoint,
    ) -> Result<SerializedProtosEndpoint, Box<Error>> {
        let mut endpoint_data: Vec<u8> = Vec::new();
        endpoint.encode(&mut endpoint_data)?;
        Ok(SerializedProtosEndpoint { data: endpoint_data })
    }

    fn get_serialized_protos_scaii_packet(
        &mut self,
        pkt: &protos::ScaiiPacket,
    ) -> Result<SerializedProtosScaiiPacket, Box<Error>> {
        let mut pkt_data: Vec<u8> = Vec::new();
        pkt.encode(&mut pkt_data)?;
        Ok(SerializedProtosScaiiPacket { data: pkt_data })
    }

    fn handle_pkt(&mut self, pkt: &ScaiiPacket) -> Result<(), Box<Error>> {
        let src_endpoint = &pkt.src;
        let ser_protos_src_endpoint = self.get_serialized_protos_endpoint(src_endpoint)?;
        let specific_msg = &pkt.specific_msg;
        match *specific_msg {
            Some(SpecificMsg::RecorderConfig(_)) => {
                self.is_recording = true;
                let ser_protos_scaii_pkt = self.get_serialized_protos_scaii_packet(pkt)?;
                let replay_header = ReplayHeader { configs: ser_protos_scaii_pkt };
                let replay_action = ReplayAction::Header(replay_header);
                self.start_recording(&replay_action)?;
            }
            Some(SpecificMsg::SerResp(ref ser_resp)) => {
                if self.is_recording {
                    let ser_protos_ser_resp =
                        self.get_serialized_protos_serialization_response(ser_resp)?;
                    let ser_info = SerializationInfo {
                        source: ser_protos_src_endpoint,
                        data: ser_protos_ser_resp,
                    };
                    if let Some(SerializationInfo { .. }) = self.staged_ser_info {
                        return Err(Box::new(RecorderError::new(
                            "Received consecutive SerializationInfo packets - expected RecorderStep in between.",
                        )));
                    }
                    self.staged_ser_info = Some(ser_info);
                }
            }
            Some(SpecificMsg::RecorderStep(ref rec_step)) => {
                if self.is_recording {
                    if let Some(SerializationInfo { .. }) = self.staged_ser_info {
                        self.save_keyframe(rec_step)?;
                    } else {
                        let game_action = self.get_game_action_for_protos_action(rec_step)?;
                        let replay_action = ReplayAction::Delta(game_action);
                        self.persist_replay_action(&replay_action)?;
                    }
                }
            }
            Some(SpecificMsg::GameComplete(_)) => {
                self.stop_recording();
            }
            _ => {}
        }
        Ok(())
    }

    fn stop_recording(&mut self) {
        self.writable_file = None;
    }

    fn start_recording(&mut self, header_replay_action: &ReplayAction) -> Result<(), Box<Error>> {
        println!("recording header.");
        if self.file_path == None {
            return Err(Box::new(RecorderError::new(
                "RecorderManager.file_path not specified prior to start of recording.",
            )));
        }
        let path = self.file_path.clone().unwrap();
        let f = File::create(&path).expect("could not write to replay file");
        self.writable_file = Some(f);
        self.persist_replay_action(header_replay_action)?;
        Ok(())
    }

    fn persist_replay_action(&mut self, replay_action: &ReplayAction) -> Result<(), Box<Error>> {
        println!("persisting replayAction {:?}", replay_action);
        match self.writable_file {
            None => {
                return Err(Box::new(RecorderError::new(
                    "RecorderManager.writable_file not open for recording replay action.",
                )));
            }
            Some(ref mut file) => {
                let encoded: Vec<u8> = serialize(replay_action, Infinite).unwrap();
                let data_size = encoded.len();
                let write_result = file.write(&encoded);
                if write_result.unwrap() != data_size {
                    return Err(Box::new(RecorderError::new(
                        "could not write entire replay_action to replay file.",
                    )));
                }
            }
        }
        Ok(())
    }

    fn get_game_action_for_protos_action(
        &mut self,
        rec_step: &RecorderStep,
    ) -> Result<GameAction, Box<Error>> {
        if rec_step.is_decision_point {
            if rec_step.action == None {
                return Err(Box::new(RecorderError::new(
                    "Malformed RecordStep: no action present but is_decision_point was true.",
                )));
            }
            let serialized_protos_action = self.get_serialized_protos_action(
                &rec_step.action.clone().unwrap(),
            )?;
            Ok(GameAction::DecisionPoint(serialized_protos_action))
        } else {
            Ok(GameAction::Step)
        }
    }

    fn save_keyframe(&mut self, rec_step: &RecorderStep) -> Result<(), Box<Error>> {
        if rec_step.action == None {
            return Err(Box::new(RecorderError::new(
                "Cannot create keyFrame to store - action missing.",
            )));
        }
        let game_action = self.get_game_action_for_protos_action(rec_step)?;
        let ser_info = self.staged_ser_info.clone();
        if ser_info == None {
            return Err(Box::new(RecorderError::new(
                "Cannot create keyFrame to store - ser_info missing.",
            )));
        }
        let replay_action = ReplayAction::Keyframe(ser_info.clone().unwrap(), game_action);
        self.persist_replay_action(&replay_action)?;
        self.staged_ser_info = None;
        Ok(())
    }
}

impl Module for RecorderManager {
    fn process_msg(&mut self, msg: &ScaiiPacket) -> Result<(), Box<Error>> {
        println!("recorderManager handling packet");
        self.handle_pkt(msg)
    }

    /// return empty messages
    fn get_messages(&mut self) -> MultiMessage {
        let pkts: Vec<ScaiiPacket> = Vec::new();
        MultiMessage { packets: pkts }
    }
}

impl Recorder for RecorderManager {}

pub fn get_default_replay_file_path() -> Result<PathBuf, Box<Error>> {
    let mut replay_dir_path_buf = get_default_replay_dir()?;
    replay_dir_path_buf.push("replay_data.sky");
    Ok(replay_dir_path_buf)
}

pub fn get_default_replay_dir() -> Result<PathBuf, Box<Error>> {
    let mut scaii_root = util::get_scaii_root()?;
    scaii_root.push("core");
    scaii_root.push("replay_data");
    Ok(scaii_root)
}

fn ensure_dir_exists(path_buf: &PathBuf) -> Result<(), Box<Error>> {
    if !path_buf.as_path().exists() {
        fs::create_dir_all(path_buf.as_path())?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    return v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia")))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS {
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}
<commit_msg>Add a comment explaining why SecRandomCopyBytes is not used on MacOS<commit_after>use crate::mem;
use crate::slice;

pub fn hashmap_random_keys() -> (u64, u64) {
    let mut v = (0, 0);
    unsafe {
        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
                                             mem::size_of_val(&v));
        imp::fill_bytes(view);
    }
    return v
}

#[cfg(all(unix,
          not(target_os = "ios"),
          not(target_os = "openbsd"),
          not(target_os = "freebsd"),
          not(target_os = "fuchsia")))]
mod imp {
    use crate::fs::File;
    use crate::io::Read;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        unsafe {
            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
        }
    }

    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { false }

    #[cfg(any(target_os = "linux", target_os = "android"))]
    fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
        use crate::sync::atomic::{AtomicBool, Ordering};
        use crate::sys::os::errno;

        static GETRANDOM_UNAVAILABLE: AtomicBool = AtomicBool::new(false);
        if GETRANDOM_UNAVAILABLE.load(Ordering::Relaxed) {
            return false;
        }

        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else if err == libc::ENOSYS {
                    GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
                    return false;
                } else if err == libc::EAGAIN {
                    return false;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
        true
    }

    pub fn fill_bytes(v: &mut [u8]) {
        // getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
        // meaning it would have blocked because the non-blocking pool (urandom)
        // has not initialized in the kernel yet due to a lack of entropy. The
        // fallback we do here is to avoid blocking applications which could
        // depend on this call without ever knowing they do and don't have a
        // work around. The PRNG of /dev/urandom will still be used but over a
        // possibly predictable entropy pool.
        if getrandom_fill_bytes(v) {
            return;
        }

        // getrandom failed because it is permanently or temporarily (because
        // of missing entropy) unavailable. Open /dev/urandom, read from it,
        // and close it again.
        let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom");
        file.read_exact(v).expect("failed to read /dev/urandom")
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use crate::sys::os::errno;

    pub fn fill_bytes(v: &mut [u8]) {
        // getentropy(2) permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let ret = unsafe {
                libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
            };
            if ret == -1 {
                panic!("unexpected getentropy error: {}", errno());
            }
        }
    }
}

// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(target_os = "ios")]
mod imp {
    use crate::io;
    use crate::ptr;
    use libc::{c_int, size_t};

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    extern {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t,
                              bytes: *mut u8) -> c_int;
    }

    pub fn fill_bytes(v: &mut [u8]) {
        let ret = unsafe {
            SecRandomCopyBytes(kSecRandomDefault,
                               v.len(),
                               v.as_mut_ptr())
        };
        if ret == -1 {
            panic!("couldn't generate random bytes: {}",
                   io::Error::last_os_error());
        }
    }
}

#[cfg(target_os = "freebsd")]
mod imp {
    use crate::ptr;

    pub fn fill_bytes(v: &mut [u8]) {
        let mib = [libc::CTL_KERN, libc::KERN_ARND];
        // kern.arandom permits a maximum buffer size of 256 bytes
        for s in v.chunks_mut(256) {
            let mut s_len = s.len();
            let ret = unsafe {
                libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
                             s.as_mut_ptr() as *mut _, &mut s_len,
                             ptr::null(), 0)
            };
            if ret == -1 || s_len != s.len() {
                panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
                       ret, s.len(), s_len);
            }
        }
    }
}

#[cfg(target_os = "fuchsia")]
mod imp {
    #[link(name = "zircon")]
    extern {
        fn zx_cprng_draw(buffer: *mut u8, len: usize);
    }

    pub fn fill_bytes(v: &mut [u8]) {
        unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
    }
}
<|endoftext|>


<commit_before>use hypercall::hypercall2;
use hypercall::HypercallKind;

use defs::{Ulong, EvtchnPort};

mod dispatcher;

#[allow(dead_code)]
enum EventOp {
    BindInterdomain = 0,
    BindVirq = 1,
    BindPirq = 2,
    Close = 3,
    Send = 4,
    Status = 5,
    AllocUnbound = 6,
    BindIpi = 7,
    BindVcpu = 8,
    Unmask = 9,
    Reset = 10,
    InitControl = 11,
    ExpandArray = 12,
    SetPriority = 13,
}

#[repr(C)]
struct EvtchnSend {
    port: EvtchnPort,
}

#[inline]
fn event_channel_op(op: EventOp, event: Ulong) -> i32 {
    unsafe {
        hypercall2(HypercallKind::EventChannelOp, op as Ulong, event) as i32
    }
}

pub fn send(port: EvtchnPort) -> i32 {
    let ev: EvtchnSend = EvtchnSend {
        port: port,
    };
    let ev_ptr = &ev as *const EvtchnSend;

    event_channel_op(EventOp::Send, ev_ptr as Ulong)
}
<commit_msg>libxen: Expose dispatcher global variable<commit_after>use hypercall::hypercall2;
use hypercall::HypercallKind;

use defs::{Ulong, EvtchnPort};

mod dispatcher;

pub use self::dispatcher::Dispatcher;

static mut DISPATCHER: Dispatcher = Dispatcher::new();

pub fn dispatcher<'a>() -> &'a mut Dispatcher {
    unsafe {
        &mut DISPATCHER
    }
}

#[allow(dead_code)]
enum EventOp {
    BindInterdomain = 0,
    BindVirq = 1,
    BindPirq = 2,
    Close = 3,
    Send = 4,
    Status = 5,
    AllocUnbound = 6,
    BindIpi = 7,
    BindVcpu = 8,
    Unmask = 9,
    Reset = 10,
    InitControl = 11,
    ExpandArray = 12,
    SetPriority = 13,
}

#[repr(C)]
struct EvtchnSend {
    port: EvtchnPort,
}

#[inline]
fn event_channel_op(op: EventOp, event: Ulong) -> i32 {
    unsafe {
        hypercall2(HypercallKind::EventChannelOp, op as Ulong, event) as i32
    }
}

pub fn send(port: EvtchnPort) -> i32 {
    let ev: EvtchnSend = EvtchnSend {
        port: port,
    };
    let ev_ptr = &ev as *const EvtchnSend;

    event_channel_op(EventOp::Send, ev_ptr as Ulong)
}
<|endoftext|>