<commit_before>use std::ffi;
use std::mem;
use std::ptr;
use std::slice;

use image::{RgbaImage, Pixel, Rgba};
use libc;
use x11::xlib;

pub const ALL_PLANES: libc::c_ulong = !0;

pub struct Display {
    handle: *mut xlib::Display,
}

pub struct Image {
    handle: *mut xlib::XImage,
}

pub enum PixelFmtError {
    InvalidDepth,
    InvalidChannelMask,
}

impl Display {
    pub fn open(name: Option<ffi::CString>) -> Option<Display> {
        unsafe {
            let name = match name {
                None => ptr::null(),
                Some(cstr) => cstr.as_ptr(),
            };
            let d = xlib::XOpenDisplay(name);

            if d.is_null() {
                return None;
            }

            Some(Display {
                handle: d,
            })
        }
    }

    pub fn get_default_root(&self) -> xlib::Window {
        unsafe {
            xlib::XDefaultRootWindow(self.handle)
        }
    }

    pub fn get_window_attributes(&self, window: xlib::Window) -> xlib::XWindowAttributes {
        unsafe {
            let mut attrs = mem::uninitialized();
            xlib::XGetWindowAttributes(self.handle, window, &mut attrs);
            attrs
        }
    }

    pub fn get_image(&self, window: xlib::Window,
                     x: libc::c_int, y: libc::c_int,
                     w: libc::c_uint, h: libc::c_uint,
                     plane_mask: libc::c_ulong,
                     format: libc::c_int) -> Option<Image> {
        unsafe {
            let image = xlib::XGetImage(self.handle, window, x, y, w, h, plane_mask, format);

            if image.is_null() {
                return None;
            }

            Some(Image::from_raw_ximage(image))
        }
    }
}

impl Drop for Display {
    fn drop(&mut self) {
        unsafe {
            xlib::XCloseDisplay(self.handle);
        }
    }
}

impl Image {
    pub fn from_raw_ximage(ximage: *mut xlib::XImage) -> Image {
        Image {
            handle: ximage,
        }
    }

    pub fn into_image_buffer(&self) -> Result<RgbaImage, PixelFmtError> {
        unsafe {
            macro_rules! get {
                ($($a:ident),+) => ($(let $a = (*self.handle).$a;)+);
            }

            get!(width, height,
                 byte_order, depth, bytes_per_line, bits_per_pixel,
                 red_mask, green_mask, blue_mask);

            let stride = match (depth, bits_per_pixel) {
                (24, 24) => 3,
                (24, 32) | (32, 32) => 4,
                _ => return Err(PixelFmtError::InvalidDepth),
            };

            macro_rules! channel_offset {
                ($mask:expr) => (match (byte_order, $mask & 0xFFFFFFFF) {
                    (0, 0xFF) | (1, 0xFF000000) => 0,
                    (0, 0xFF00) | (1, 0xFF0000) => 1,
                    (0, 0xFF0000) | (1, 0xFF00) => 2,
                    (0, 0xFF000000) | (1, 0xFF) => 3,
                    _ => return Err(PixelFmtError::InvalidChannelMask),
                })
            }
            let red_offset = channel_offset!(red_mask);
            let green_offset = channel_offset!(green_mask);
            let blue_offset = channel_offset!(blue_mask);
            let alpha_offset = channel_offset!(!(red_mask | green_mask | blue_mask));

            let size = (bytes_per_line * height) as usize;
            let data = slice::from_raw_parts((*self.handle).data as *const u8, size);

            Ok(RgbaImage::from_fn(width as u32, height as u32, |x, y| {
                macro_rules! subpixel {
                    ($channel_offset:ident) => (data[(y * bytes_per_line as u32
                                                + x * stride as u32
                                                + $channel_offset) as usize]);
                }
                Rgba::from_channels(subpixel!(red_offset),
                                    subpixel!(green_offset),
                                    subpixel!(blue_offset),
                                    if depth == 24 { 0xFF } else { subpixel!(alpha_offset) })
            }))
        }
    }
}

impl Drop for Image {
    fn drop(&mut self) {
        unsafe {
            xlib::XDestroyImage(self.handle);
        }
    }
}
<commit_msg>Add comments to the monster<commit_after>use std::ffi;
use std::mem;
use std::ptr;
use std::slice;

use image::{RgbaImage, Pixel, Rgba};
use libc;
use x11::xlib;

pub const ALL_PLANES: libc::c_ulong = !0;

pub struct Display {
    handle: *mut xlib::Display,
}

pub struct Image {
    handle: *mut xlib::XImage,
}

pub enum PixelFmtError {
    InvalidDepth,
    InvalidChannelMask,
}

impl Display {
    pub fn open(name: Option<ffi::CString>) -> Option<Display> {
        unsafe {
            let name = match name {
                None => ptr::null(),
                Some(cstr) => cstr.as_ptr(),
            };
            let d = xlib::XOpenDisplay(name);

            if d.is_null() {
                return None;
            }

            Some(Display {
                handle: d,
            })
        }
    }

    pub fn get_default_root(&self) -> xlib::Window {
        unsafe {
            xlib::XDefaultRootWindow(self.handle)
        }
    }

    pub fn get_window_attributes(&self, window: xlib::Window) -> xlib::XWindowAttributes {
        unsafe {
            let mut attrs = mem::uninitialized();
            xlib::XGetWindowAttributes(self.handle, window, &mut attrs);
            attrs
        }
    }

    pub fn get_image(&self, window: xlib::Window,
                     x: libc::c_int, y: libc::c_int,
                     w: libc::c_uint, h: libc::c_uint,
                     plane_mask: libc::c_ulong,
                     format: libc::c_int) -> Option<Image> {
        unsafe {
            let image = xlib::XGetImage(self.handle, window, x, y, w, h, plane_mask, format);

            if image.is_null() {
                return None;
            }

            Some(Image::from_raw_ximage(image))
        }
    }
}

impl Drop for Display {
    fn drop(&mut self) {
        unsafe {
            xlib::XCloseDisplay(self.handle);
        }
    }
}

impl Image {
    pub fn from_raw_ximage(ximage: *mut xlib::XImage) -> Image {
        Image {
            handle: ximage,
        }
    }

    pub fn into_image_buffer(&self) -> Result<RgbaImage, PixelFmtError> {
        unsafe {
            // Extract values from the XImage into our own scope
            macro_rules! get {
                ($($a:ident),+) => ($(let $a = (*self.handle).$a;)+);
            }
            get!(width, height,
                 byte_order, depth, bytes_per_line, bits_per_pixel,
                 red_mask, green_mask, blue_mask);

            // Pixel size
            let stride = match (depth, bits_per_pixel) {
                (24, 24) => 3,
                (24, 32) | (32, 32) => 4,
                _ => return Err(PixelFmtError::InvalidDepth),
            };

            // Compute subpixel offsets into each pixel according the the bitmasks X gives us
            // Only 8 bit, byte-aligned values are supported
            // Truncate masks to the lower 32 bits as that is the maximum pixel size
            macro_rules! channel_offset {
                ($mask:expr) => (match (byte_order, $mask & 0xFFFFFFFF) {
                    (0, 0xFF) | (1, 0xFF000000) => 0,
                    (0, 0xFF00) | (1, 0xFF0000) => 1,
                    (0, 0xFF0000) | (1, 0xFF00) => 2,
                    (0, 0xFF000000) | (1, 0xFF) => 3,
                    _ => return Err(PixelFmtError::InvalidChannelMask),
                })
            }
            let red_offset = channel_offset!(red_mask);
            let green_offset = channel_offset!(green_mask);
            let blue_offset = channel_offset!(blue_mask);
            let alpha_offset = channel_offset!(!(red_mask | green_mask | blue_mask));

            // Wrap the pixel buffer into a slice
            let size = (bytes_per_line * height) as usize;
            let data = slice::from_raw_parts((*self.handle).data as *const u8, size);

            // Finally, generate the image object
            Ok(RgbaImage::from_fn(width as u32, height as u32, |x, y| {
                macro_rules! subpixel {
                    ($channel_offset:ident) => (data[(y * bytes_per_line as u32
                                                + x * stride as u32
                                                + $channel_offset) as usize]);
                }
                Rgba::from_channels(subpixel!(red_offset),
                                    subpixel!(green_offset),
                                    subpixel!(blue_offset),
                                    // Make the alpha channel fully opaque if none is provided
                                    if depth == 24 { 0xFF } else { subpixel!(alpha_offset) })
            }))
        }
    }
}

impl Drop for Image {
    fn drop(&mut self) {
        unsafe {
            xlib::XDestroyImage(self.handle);
        }
    }
}
<|endoftext|>


<commit_before>const DELTA: u32 = 0x9E3779B9;

fn to_bytes(v: &Vec<u32>, include_length: bool) -> Vec<u8> {
    let length: u32 = v.len() as u32;
    let mut n: u32 = length << 2;
    if include_length {
        let m: u32 = v[length as usize - 1];
        n = n - 4;
        assert!(!((m < n - 3) || (m > n)));
        n = m;
    }
    let mut bytes: Vec<u8> = vec![0; n as usize];
    for i in 0..n {
        bytes[i as usize] = (v[(i >> 2) as usize] >> ((i & 3) << 3)) as u8;
    }
    return bytes;
}

fn to_u32(bytes: &Vec<u8>, include_length: bool) -> Vec<u32> {
    let length: u32 = bytes.len() as u32;
    let mut n: u32 = length >> 2;
    if length & 3 != 0 {
        n = n + 1;
    }
    let mut v;
    if include_length {
        v = vec![0; n as usize + 1];
        v[n as usize] = length;
    } else {
        v = vec![0; n as usize];
    }
    for i in 0..length {
        v[(i >> 2) as usize] |= (bytes[i as usize] as u32) << ((i & 3) << 3) as u32;
    }
    return v;
}

fn mx(sum: u32, y: u32, z: u32, p: u32, e: u32, k: &Vec<u32>) -> u32 {
    ((z >> 5 ^ y << 2).wrapping_add(y >> 3 ^ z << 4)) ^ ((sum ^ y).wrapping_add(k[(p & 3 ^ e) as usize] ^ z))
}

fn fixk(k: &Vec<u32>) -> Vec<u32> {
    let mut key = k.clone();
    if key.len() < 4 {
        let length = key.len();
        for _ in length..4 {
            key.push(0)
        }
    }
    key
}

fn encrypt_(v: &mut Vec<u32>, k: &Vec<u32>) -> Vec<u32> {
    let length: u32 = v.len() as u32;
    let n: u32 = length - 1;
    let key: Vec<u32> = fixk(k);
    let mut e: u32;
    let mut y: u32;
    let mut z = v[n as usize];
    let mut sum: u32 = 0;
    let mut q: u32 = 6 + 52 / length;
    while q > 0 {
        sum = sum.wrapping_add(DELTA);
        e = sum >> 2 & 3;
        for p in 0..n {
            y = v[(p as usize) +1];
            v[p as usize] = v[p as usize].wrapping_add(mx(sum, y, z, (p as u32), e, &key));
            z = v[p as usize];
        }
        y = v[0];
        v[n as usize] = v[n as usize].wrapping_add(mx(sum, y, z, n, e, &key));
        z = v[n as usize];
        q = q - 1;
    }
    return v.clone();
}

fn decrypt_(v: &mut Vec<u32>, k: &Vec<u32>) -> Vec<u32>{
        let length: u32 = v.len() as u32;
        let n: u32 = length - 1;
        let key: Vec<u32> = fixk(k);
        let mut e: u32;
        let mut y: u32 = v[0];
        let mut z;
        let q: u32 = 6 + 52 / length;
        let mut sum: u32 = q.wrapping_mul(DELTA);
        while sum != 0 {
            e = sum >> 2 & 3;
            let mut p:usize = n as usize;
            while p > 0 {
                z = v[p - 1];
                v[p] = v[p].wrapping_sub(mx(sum, y, z, (p as u32), e, &key));
                y = v[p];
                p = p - 1;
            }
            z = v[n as usize];
            v[0] = v[0].wrapping_sub(mx(sum, y, z, 0, e, &key));
            y = v[0];
            sum = sum.wrapping_sub(DELTA);
        }
        return v.clone();
}

pub fn encrypt(data: &str, key: &str) -> Vec<u8> {
    let data = data.bytes().collect();
    let key = key.bytes().collect();
    to_bytes(&encrypt_(&mut to_u32(&data, true), &to_u32(&key, false)),
            false)
}

pub fn decrypt(data: &Vec<u8>, key: &str) -> Vec<u8> {
    let key = key.bytes().collect();
    to_bytes(&decrypt_(&mut to_u32(&data, false), &to_u32(&key, false)),
            true)
}

pub fn encrypt_raw(data: &Vec<u8>, key: &str) -> Vec<u8> {
    let key = key.bytes().collect();
    to_bytes(&encrypt_(&mut to_u32(&data, false), &to_u32(&key, false)),
            false)
}

pub fn decrypt_raw(data: &Vec<u8>, key: &str) -> Vec<u8> {
    let key = key.bytes().collect();
    to_bytes(&decrypt_(&mut to_u32(&data, false), &to_u32(&key, false)),
            false)
}

<commit_msg>Add documentation for new functions<commit_after>const DELTA: u32 = 0x9E3779B9;

fn to_bytes(v: &Vec<u32>, include_length: bool) -> Vec<u8> {
    let length: u32 = v.len() as u32;
    let mut n: u32 = length << 2;
    if include_length {
        let m: u32 = v[length as usize - 1];
        n = n - 4;
        assert!(!((m < n - 3) || (m > n)));
        n = m;
    }
    let mut bytes: Vec<u8> = vec![0; n as usize];
    for i in 0..n {
        bytes[i as usize] = (v[(i >> 2) as usize] >> ((i & 3) << 3)) as u8;
    }
    return bytes;
}

fn to_u32(bytes: &Vec<u8>, include_length: bool) -> Vec<u32> {
    let length: u32 = bytes.len() as u32;
    let mut n: u32 = length >> 2;
    if length & 3 != 0 {
        n = n + 1;
    }
    let mut v;
    if include_length {
        v = vec![0; n as usize + 1];
        v[n as usize] = length;
    } else {
        v = vec![0; n as usize];
    }
    for i in 0..length {
        v[(i >> 2) as usize] |= (bytes[i as usize] as u32) << ((i & 3) << 3) as u32;
    }
    return v;
}

fn mx(sum: u32, y: u32, z: u32, p: u32, e: u32, k: &Vec<u32>) -> u32 {
    ((z >> 5 ^ y << 2).wrapping_add(y >> 3 ^ z << 4)) ^ ((sum ^ y).wrapping_add(k[(p & 3 ^ e) as usize] ^ z))
}

fn fixk(k: &Vec<u32>) -> Vec<u32> {
    let mut key = k.clone();
    if key.len() < 4 {
        let length = key.len();
        for _ in length..4 {
            key.push(0)
        }
    }
    key
}

fn encrypt_(v: &mut Vec<u32>, k: &Vec<u32>) -> Vec<u32> {
    let length: u32 = v.len() as u32;
    let n: u32 = length - 1;
    let key: Vec<u32> = fixk(k);
    let mut e: u32;
    let mut y: u32;
    let mut z = v[n as usize];
    let mut sum: u32 = 0;
    let mut q: u32 = 6 + 52 / length;
    while q > 0 {
        sum = sum.wrapping_add(DELTA);
        e = sum >> 2 & 3;
        for p in 0..n {
            y = v[(p as usize) +1];
            v[p as usize] = v[p as usize].wrapping_add(mx(sum, y, z, (p as u32), e, &key));
            z = v[p as usize];
        }
        y = v[0];
        v[n as usize] = v[n as usize].wrapping_add(mx(sum, y, z, n, e, &key));
        z = v[n as usize];
        q = q - 1;
    }
    return v.clone();
}

fn decrypt_(v: &mut Vec<u32>, k: &Vec<u32>) -> Vec<u32>{
        let length: u32 = v.len() as u32;
        let n: u32 = length - 1;
        let key: Vec<u32> = fixk(k);
        let mut e: u32;
        let mut y: u32 = v[0];
        let mut z;
        let q: u32 = 6 + 52 / length;
        let mut sum: u32 = q.wrapping_mul(DELTA);
        while sum != 0 {
            e = sum >> 2 & 3;
            let mut p:usize = n as usize;
            while p > 0 {
                z = v[p - 1];
                v[p] = v[p].wrapping_sub(mx(sum, y, z, (p as u32), e, &key));
                y = v[p];
                p = p - 1;
            }
            z = v[n as usize];
            v[0] = v[0].wrapping_sub(mx(sum, y, z, 0, e, &key));
            y = v[0];
            sum = sum.wrapping_sub(DELTA);
        }
        return v.clone();
}

pub fn encrypt(data: &str, key: &str) -> Vec<u8> {
    let data = data.bytes().collect();
    let key = key.bytes().collect();
    to_bytes(&encrypt_(&mut to_u32(&data, true), &to_u32(&key, false)),
            false)
}

pub fn decrypt(data: &Vec<u8>, key: &str) -> Vec<u8> {
    let key = key.bytes().collect();
    to_bytes(&decrypt_(&mut to_u32(&data, false), &to_u32(&key, false)),
            true)
}

/// Encrypt a u8 vector with XXTEA
///
/// *Note:* XXTEA works on 32 bit words. If input is not evenly dividable by
/// four, it will be padded with zeroes. Padding information is lost after the
/// encryption and this needs to be taken into consideration when decrypting
/// messages.
///
/// # Arguments
///
/// * `data` - The data to be encrypted
/// * `key` - encryption key
///
/// # Example
///
/// ```
/// let key : &str = "SecretKey";
/// let data : [u8; 5] = [11, 13, 0, 14, 15];
///
/// let encrypted_data = xxtea::encrypt_raw(&data.to_vec(), &key);
/// // encrypted data will be 8 bytes (3 zeroes appended to the end)
/// println!("Encrypted data: {:?}", encrypted_data);
/// ```
///
pub fn encrypt_raw(data: &Vec<u8>, key: &str) -> Vec<u8> {
    let key = key.bytes().collect();
    to_bytes(&encrypt_(&mut to_u32(&data, false), &to_u32(&key, false)),
            false)
}

/// Decrypt a u8 vector with XXTEA
///
/// The output isn't verified for correctness, thus additional checks needs to
/// be performed on the output.
///
/// # Arguments
///
/// * `data` - The data to be decrypted
/// * `key` - encryption key
///
/// # Example
///
/// ```
/// let key : &str = "SecretKey";
/// let data : [u8; 5] = [11, 13, 0, 14, 15];
///
/// let decrypted_data = xxtea::decrypt_raw(&data.to_vec(), &key);
/// println!("Decrypted data: {:?}", decrypted_data);
/// ```
///
pub fn decrypt_raw(data: &Vec<u8>, key: &str) -> Vec<u8> {
    let key = key.bytes().collect();
    to_bytes(&decrypt_(&mut to_u32(&data, false), &to_u32(&key, false)),
            false)
}

<|endoftext|>


<commit_before>use crate::beacon_chain::BeaconChain;
use crate::error;
use crate::messages::NodeMessage;
use crate::service::{NetworkMessage, OutgoingMessage};
use crate::sync::SimpleSync;
use crossbeam_channel::{unbounded as channel, Sender};
use futures::future;
use futures::prelude::*;
use libp2p::{
    rpc::{RPCMethod, RPCRequest, RPCResponse},
    HelloMessage, PeerId, RPCEvent,
};
use slog::warn;
use slog::{debug, trace};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use types::Hash256;

/// Timeout for RPC requests.
const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);

/// Handles messages received from the network and client and organises syncing.
pub struct MessageHandler {
    /// Currently loaded and initialised beacon chain.
    chain: Arc<BeaconChain>,
    /// The syncing framework.
    sync: SimpleSync,
    /// The network channel to relay messages to the Network service.
    network_send: crossbeam_channel::Sender<NetworkMessage>,
    /// A mapping of peers we have sent an RPC request to.
    requests: HashMap<PeerId, Vec<RPCRequestInfo>>,
    /// A counter of request id for each peer.
    request_ids: HashMap<PeerId, u64>,
    /// The `MessageHandler` logger.
    log: slog::Logger,
}

/// RPC request information
pub struct RPCRequestInfo {
    /// The id of the request
    id: u64,
    /// The time the request was sent, to check ttl.
    request_time: Instant,
}

/// Types of messages the handler can receive.
#[derive(Debug, Clone)]
pub enum HandlerMessage {
    /// We have initiated a connection to a new peer.
    PeerDialed(PeerId),
    /// Peer has disconnected,
    PeerDisconnected(PeerId),
    /// A Node message has been received.
    Message(PeerId, NodeMessage),
    /// An RPC response/request has been received.
    RPC(PeerId, RPCEvent),
}

impl MessageHandler {
    /// Initializes and runs the MessageHandler.
    pub fn new(
        beacon_chain: Arc<BeaconChain>,
        network_send: crossbeam_channel::Sender<NetworkMessage>,
        executor: &tokio::runtime::TaskExecutor,
        log: slog::Logger,
    ) -> error::Result<Sender<HandlerMessage>> {
        debug!(log, "Service starting");

        let (handler_send, handler_recv) = channel();

        // Initialise sync and begin processing in thread
        // generate the Message handler
        let sync = SimpleSync::new(beacon_chain.clone());

        let mut handler = MessageHandler {
            // TODO: The handler may not need a chain, perhaps only sync?
            chain: beacon_chain.clone(),
            sync,
            network_send,
            requests: HashMap::new(),
            request_ids: HashMap::new(),
            log: log.clone(),
        };

        // spawn handler task
        // TODO: Handle manual termination of thread
        executor.spawn(future::poll_fn(move || -> Result<_, _> {
            loop {
                handler.handle_message(handler_recv.recv().map_err(|_| {
                    debug!(log, "Network message handler terminated.");
                })?);
            }
        }));

        Ok(handler_send)
    }

    fn handle_message(&mut self, message: HandlerMessage) {
        match message {
            // we have initiated a connection to a peer
            HandlerMessage::PeerDialed(peer_id) => {
                self.send_hello_request(peer_id);
            }
            // we have received an RPC message request/response
            HandlerMessage::RPC(peer_id, rpc_event) => {
                self.handle_rpc_message(peer_id, rpc_event);
            }
            //TODO: Handle all messages
            _ => {}
        }
    }

    fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) {
        match rpc_message {
            RPCEvent::Request {
                id,
                method_id: _, // TODO: Clean up RPC Message types, have a cleaner type by this point.
                body,
            } => self.handle_rpc_request(peer_id, id, body),
            RPCEvent::Response {
                id,
                method_id: _,
                result,
            } => self.handle_rpc_response(peer_id, id, result),
        }
    }

    /// A new RPC request has been received from the network.
    fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) {
        match request {
            RPCRequest::Hello(hello_message) => {
                self.handle_hello_response(peer_id, id, hello_message)
            }
        }
    }

    /// An RPC response has been received from the network.
    // we match on id and ignore responses past the timeout.
    fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {}

    fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) {
        /*
                // if response id is not in our list, ignore (likely RPC timeout)
                match self.requests.get(peer_id) {
                    None => return;
                    Some(rpc_info) => {
                        if rpc_info.con

        */

    }

    /// Sends a HELLO RPC request to a newly connected peer.
    fn send_hello_request(&mut self, peer_id: PeerId) {
        // generate a unique id for the peer
        let id = {
            let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0);
            let id = borrowed_id.clone();
            //increment the counter
            *borrowed_id += 1;
            id
        };
        // register RPC request
        {
            let requests = self
                .requests
                .entry(peer_id.clone())
                .or_insert_with(|| vec![]);
            requests.push(RPCRequestInfo {
                id: id.clone(),
                request_time: Instant::now(),
            });
        }

        // build the rpc request
        let rpc_event = RPCEvent::Request {
            id,
            method_id: RPCMethod::Hello.into(),
            body: RPCRequest::Hello(self.sync.generate_hello()),
        };

        // send the hello request to the network
        trace!(self.log, "Sending HELLO message to peer {:?}", peer_id);
        self.send_rpc(peer_id, rpc_event);
    }

    /// Sends an RPC request/response to the network server.
    fn send_rpc(&self, peer_id: PeerId, rpc_event: RPCEvent) {
        self.network_send
            .send(NetworkMessage::Send(
                peer_id,
                OutgoingMessage::RPC(rpc_event),
            ))
            .unwrap_or_else(|_| {
                warn!(
                    self.log,
                    "Could not send RPC message to the network service"
                )
            });
    }
}
<commit_msg>Basic node handshake<commit_after>use crate::beacon_chain::BeaconChain;
use crate::error;
use crate::messages::NodeMessage;
use crate::service::{NetworkMessage, OutgoingMessage};
use crate::sync::SimpleSync;
use crossbeam_channel::{unbounded as channel, Sender};
use futures::future;
use futures::prelude::*;
use libp2p::{
    rpc::{RPCMethod, RPCRequest, RPCResponse},
    HelloMessage, PeerId, RPCEvent,
};
use slog::warn;
use slog::{debug, trace};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use types::Hash256;

/// Timeout for RPC requests.
const REQUEST_TIMEOUT: Duration = Duration::from_secs(30);
/// Timeout before banning a peer for non-identification.
const HELLO_TIMEOUT: Duration = Duration::from_secs(30);

/// Handles messages received from the network and client and organises syncing.
pub struct MessageHandler {
    /// Currently loaded and initialised beacon chain.
    chain: Arc<BeaconChain>,
    /// The syncing framework.
    sync: SimpleSync,
    /// The network channel to relay messages to the Network service.
    network_send: crossbeam_channel::Sender<NetworkMessage>,
    /// A mapping of peers and the RPC id we have sent an RPC request to.
    requests: HashMap<(PeerId, u64), Instant>,
    /// A mapping of HELLO requests we have sent. We drop/ban peers if they do not response
    /// within the timeout
    hello_requests: HashMap<PeerId, Instant>,
    /// A counter of request id for each peer.
    request_ids: HashMap<PeerId, u64>,
    /// The `MessageHandler` logger.
    log: slog::Logger,
}

/// Types of messages the handler can receive.
#[derive(Debug, Clone)]
pub enum HandlerMessage {
    /// We have initiated a connection to a new peer.
    PeerDialed(PeerId),
    /// Peer has disconnected,
    PeerDisconnected(PeerId),
    /// A Node message has been received.
    Message(PeerId, NodeMessage),
    /// An RPC response/request has been received.
    RPC(PeerId, RPCEvent),
}

impl MessageHandler {
    /// Initializes and runs the MessageHandler.
    pub fn new(
        beacon_chain: Arc<BeaconChain>,
        network_send: crossbeam_channel::Sender<NetworkMessage>,
        executor: &tokio::runtime::TaskExecutor,
        log: slog::Logger,
    ) -> error::Result<Sender<HandlerMessage>> {
        debug!(log, "Service starting");

        let (handler_send, handler_recv) = channel();

        // Initialise sync and begin processing in thread
        // generate the Message handler
        let sync = SimpleSync::new(beacon_chain.clone());

        let mut handler = MessageHandler {
            // TODO: The handler may not need a chain, perhaps only sync?
            chain: beacon_chain.clone(),
            sync,
            network_send,
            requests: HashMap::new(),
            hello_requests: HashMap::new(),
            request_ids: HashMap::new(),

            log: log.clone(),
        };

        // spawn handler task
        // TODO: Handle manual termination of thread
        executor.spawn(future::poll_fn(move || -> Result<_, _> {
            loop {
                handler.handle_message(handler_recv.recv().map_err(|_| {
                    debug!(log, "Network message handler terminated.");
                })?);
            }
        }));

        Ok(handler_send)
    }

    fn handle_message(&mut self, message: HandlerMessage) {
        match message {
            // we have initiated a connection to a peer
            HandlerMessage::PeerDialed(peer_id) => {
                self.send_hello_request(peer_id);
            }
            // we have received an RPC message request/response
            HandlerMessage::RPC(peer_id, rpc_event) => {
                self.handle_rpc_message(peer_id, rpc_event);
            }
            //TODO: Handle all messages
            _ => {}
        }
    }

    fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) {
        match rpc_message {
            RPCEvent::Request {
                id,
                method_id: _, // TODO: Clean up RPC Message types, have a cleaner type by this point.
                body,
            } => self.handle_rpc_request(peer_id, id, body),
            RPCEvent::Response {
                id,
                method_id: _,
                result,
            } => self.handle_rpc_response(peer_id, id, result),
        }
    }

    /// A new RPC request has been received from the network.
    fn handle_rpc_request(&mut self, peer_id: PeerId, id: u64, request: RPCRequest) {
        match request {
            RPCRequest::Hello(hello_message) => {
                self.handle_hello_response(peer_id, id, hello_message)
            }
        }
    }

    /// An RPC response has been received from the network.
    // we match on id and ignore responses past the timeout.
    fn handle_rpc_response(&mut self, peer_id: PeerId, id: u64, response: RPCResponse) {}

    fn handle_hello_response(&mut self, peer_id: PeerId, id: u64, response: HelloMessage) {
        if self.hello_requests.remove(&peer_id).is_none() {
            // if response id is not in our list, ignore (likely RPC timeout)
            return;
        }

        debug!(self.log, "Hello response received from peer: {:?}", peer_id);
        // validate peer - decide whether to drop/ban or add to sync
    }

    /// Sends a HELLO RPC request to a newly connected peer.
    fn send_hello_request(&mut self, peer_id: PeerId) {
        // generate a unique id for the peer
        let id = {
            let borrowed_id = self.request_ids.entry(peer_id.clone()).or_insert_with(|| 0);
            let id = borrowed_id.clone();
            //increment the counter
            *borrowed_id += 1;
            id
        };
        // register RPC Hello request
        self.requests.insert((peer_id.clone(), id), Instant::now());
        debug!(
            self.log,
            "Hello request registered with peer: {:?}", peer_id
        );

        // build the rpc request
        let rpc_event = RPCEvent::Request {
            id,
            method_id: RPCMethod::Hello.into(),
            body: RPCRequest::Hello(self.sync.generate_hello()),
        };

        // send the hello request to the network
        trace!(self.log, "Sending HELLO message to peer {:?}", peer_id);
        self.send_rpc(peer_id, rpc_event);
    }

    /// Sends an RPC request/response to the network server.
    fn send_rpc(&self, peer_id: PeerId, rpc_event: RPCEvent) {
        self.network_send
            .send(NetworkMessage::Send(
                peer_id,
                OutgoingMessage::RPC(rpc_event),
            ))
            .unwrap_or_else(|_| {
                warn!(
                    self.log,
                    "Could not send RPC message to the network service"
                )
            });
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::error;
use std::path::{Path, PathBuf};
use std::result;
use std::str::{self, FromStr};

use libarchive::writer;
use libarchive::reader::{self, Reader};
use libarchive::archive::{Entry, ReadFilter, ReadFormat, ExtractOption, ExtractOptions};
use regex::Regex;

use error::{Error, Result};
use crypto::{artifact, hash};
use package::{Identifiable, PackageIdent, PackageTarget, MetaFile};

lazy_static! {
    static ref METAFILE_REGXS: HashMap<MetaFile, Regex> = {
        let mut map = HashMap::new();
        map.insert(MetaFile::CFlags, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::CFlags)).unwrap());
        map.insert(MetaFile::Config, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Config)).unwrap());
        map.insert(MetaFile::Deps, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Deps)).unwrap());
        map.insert(MetaFile::TDeps, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::TDeps)).unwrap());
        map.insert(MetaFile::Exposes, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Exposes)).unwrap());
        map.insert(MetaFile::Ident, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Ident)).unwrap());
        map.insert(MetaFile::LdRunPath, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdRunPath)).unwrap());
        map.insert(MetaFile::LdFlags, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdFlags)).unwrap());
        map.insert(MetaFile::Manifest, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Manifest)).unwrap());
        map.insert(MetaFile::Path, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Path)).unwrap());
        map.insert(MetaFile::Target, Regex::new(&format!(r"^hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Target)).unwrap());
        map
    };
}

type Metadata = HashMap<MetaFile, String>;

#[derive(Debug)]
pub struct PackageArchive {
    pub path: PathBuf,
    metadata: Option<Metadata>,
}

impl PackageArchive {
    pub fn new<P: Into<PathBuf>>(path: P) -> Self {
        PackageArchive {
            path: path.into(),
            metadata: None,
        }
    }

    /// Calculate and return the checksum of the package archive in base64 format.
    ///
    /// # Failures
    ///
    /// * If the archive cannot be read
    pub fn checksum(&self) -> Result<String> {
        hash::hash_file(&self.path)
    }

    pub fn cflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::CFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn config(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Config) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    /// Returns a list of package identifiers representing the runtime package dependencies for
    /// this archive.
    ///
    /// # Failures
    ///
    /// * If a `DEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn deps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::Deps)
    }

    /// Returns a list of package identifiers representing the transitive runtime package
    /// dependencies for this archive.
    ///
    /// # Failures
    ///
    /// * If a `TDEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn tdeps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::TDeps)
    }

    pub fn exposes(&mut self) -> Result<Vec<u16>> {
        match self.read_metadata(MetaFile::Exposes) {
            Ok(Some(data)) => {
                let ports: Vec<u16> = data.split(" ")
                    .filter_map(|port| port.parse::<u16>().ok())
                    .collect();
                Ok(ports)
            }
            Ok(None) => Ok(vec![]),
            Err(e) => Err(e),
        }
    }

    pub fn ident(&mut self) -> Result<PackageIdent> {
        match self.read_metadata(MetaFile::Ident) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Ident)),
            Ok(Some(data)) => PackageIdent::from_str(&data),
            Err(e) => Err(e),
        }
    }

    pub fn ld_run_path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdRunPath) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn ldflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn manifest(&mut self) -> Result<String> {
        match self.read_metadata(MetaFile::Manifest) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Manifest)),
            Ok(Some(data)) => Ok(data.clone()),
            Err(e) => Err(e),
        }
    }

    pub fn path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Path) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn target(&mut self) -> Result<PackageTarget> {
        match self.read_metadata(MetaFile::Target) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Target)),
            Ok(Some(data)) => PackageTarget::from_str(&data),
            Err(e) => Err(e),
        }
    }

    /// A plain string representation of the archive's file name.
    pub fn file_name(&self) -> String {
        self.path.file_name().unwrap().to_string_lossy().into_owned()
    }

    /// Given a package name and a path to a file as an `&str`, verify
    /// the files signature.
    ///
    /// # Failures
    ///
    /// * Fails if it cannot verify the signature for any reason
    pub fn verify<P: AsRef<Path>>(&self, cache_key_path: &P) -> Result<(String, String)> {
        artifact::verify(&self.path, cache_key_path)
    }

    /// Given a package name and a path to a file as an `&str`, unpack
    /// the package.
    ///
    /// # Failures
    ///
    /// * If the package cannot be unpacked
    pub fn unpack(&self, fs_root_path: Option<&Path>) -> Result<()> {
        let root = fs_root_path.unwrap_or(Path::new("/"));
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        let writer = writer::Disk::new();
        let mut extract_options = ExtractOptions::new();
        extract_options.add(ExtractOption::Time);
        extract_options.add(ExtractOption::Owner);
        extract_options.add(ExtractOption::Permissions);
        try!(writer.set_options(&extract_options));
        try!(writer.set_standard_lookup());
        try!(writer.write(&mut reader, Some(root.to_string_lossy().as_ref())));
        try!(writer.close());
        Ok(())
    }

    fn read_deps(&mut self, file: MetaFile) -> Result<Vec<PackageIdent>> {
        let mut deps: Vec<PackageIdent> = vec![];
        let filename = format!("{}", &file);
        match self.read_metadata(file) {
            Ok(Some(body)) => {
                debug!("body {} = [{}]", &filename, &body);
                let ids: Vec<String> = body.lines().map(|d| d.to_string()).collect();
                for id in &ids {
                    debug!("id {} = [{}]", &filename, &id);
                    let package = try!(PackageIdent::from_str(id));
                    if !package.fully_qualified() {
                        // JW TODO: use a more appropriate erorr to describe the invalid
                        // user input here. (user because a package was generated by a user
                        // and read into program)
                        return Err(Error::InvalidPackageIdent(package.to_string()));
                    }
                    deps.push(package);
                }
                Ok(deps)
            }
            Ok(None) => Ok(vec![]),
            Err(Error::MetaFileNotFound(_)) => Ok(deps),
            Err(e) => Err(e),
        }
    }

    fn read_metadata(&mut self, file: MetaFile) -> Result<Option<&String>> {
        if let Some(ref files) = self.metadata {
            return Ok(files.get(&file));
        }
        let mut metadata = Metadata::new();
        let mut matched_count = 0u8;
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        loop {
            let mut matched_type: Option<MetaFile> = None;
            if let Some(entry) = reader.next_header() {
                for (matched, regx) in METAFILE_REGXS.iter() {
                    if regx.is_match(entry.pathname()) {
                        matched_type = Some((*matched).clone());
                        matched_count += 1;
                        break;
                    }
                }
            } else {
                break;
            }

            if matched_type.is_none() {
                continue;
            }

            let mut buf = String::new();
            loop {
                match reader.read_block() {
                    Ok(Some(bytes)) => {
                        match str::from_utf8(bytes) {
                            Ok(content) => {
                                // You used to trim. Now you don't, because you were trimming
                                // in the wrong place. Sometimes a buffer ends (or starts!) with
                                // a newline.
                                buf.push_str(content);
                            }
                            Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                        }
                    }
                    Ok(None) => {
                        debug!("content = {}", &buf);
                        // Hey, before you go - we are trimming whitespace for you. This
                        // is handy, because later on, you just want the string you want.
                        metadata.insert(matched_type.unwrap(), String::from(buf.trim()));
                        break;
                    }
                    Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                }
            }//inner loop

            if matched_count == METAFILE_REGXS.len() as u8 {
                break;
            }
        }
        self.metadata = Some(metadata);
        Ok(self.metadata.as_ref().unwrap().get(&file))
    }
}

pub trait FromArchive: Sized {
    type Error: error::Error;

    fn from_archive(archive: &mut PackageArchive) -> result::Result<Self, Self::Error>;
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use os::system::{Architecture, Platform};
    use super::*;

    #[test]
    fn reading_artifact_metadata() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let ident = hart.ident().unwrap();
        assert_eq!(ident.origin, "happyhumans");
        assert_eq!(ident.name, "possums");
        assert_eq!(ident.version, Some("8.1.4".to_string()));
        assert_eq!(ident.release, Some("20160427165340".to_string()));
    }

    pub fn root() -> PathBuf {
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests")
    }

    pub fn fixtures() -> PathBuf {
        root().join("fixtures")
    }

    #[test]
    fn reading_artifact_deps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let _ = hart.deps().unwrap();
        let _ = hart.tdeps().unwrap();
    }

    #[test]
    fn reading_artifact_large_tdeps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("unhappyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let tdeps = hart.tdeps().unwrap();
        assert_eq!(1024, tdeps.len());
    }

    #[test]
    fn reading_artifact_target() {
        let mut hart = PackageArchive::new(fixtures()
            .join("unhappyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let target = hart.target().unwrap();
        assert_eq!(target.platform, Platform::Linux);
        assert_eq!(target.architecture, Architecture::X86_64);
    }
}
<commit_msg>[core] Support leading `/` in artifact metadata lookup regexes.<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::error;
use std::path::{Path, PathBuf};
use std::result;
use std::str::{self, FromStr};

use libarchive::writer;
use libarchive::reader::{self, Reader};
use libarchive::archive::{Entry, ReadFilter, ReadFormat, ExtractOption, ExtractOptions};
use regex::Regex;

use error::{Error, Result};
use crypto::{artifact, hash};
use package::{Identifiable, PackageIdent, PackageTarget, MetaFile};

lazy_static! {
    static ref METAFILE_REGXS: HashMap<MetaFile, Regex> = {
        let mut map = HashMap::new();
        map.insert(MetaFile::CFlags, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::CFlags)).unwrap());
        map.insert(MetaFile::Config, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Config)).unwrap());
        map.insert(MetaFile::Deps, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Deps)).unwrap());
        map.insert(MetaFile::TDeps, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::TDeps)).unwrap());
        map.insert(MetaFile::Exposes, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Exposes)).unwrap());
        map.insert(MetaFile::Ident, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Ident)).unwrap());
        map.insert(MetaFile::LdRunPath, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdRunPath)).unwrap());
        map.insert(MetaFile::LdFlags, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::LdFlags)).unwrap());
        map.insert(MetaFile::Manifest, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Manifest)).unwrap());
        map.insert(MetaFile::Path, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Path)).unwrap());
        map.insert(MetaFile::Target, Regex::new(&format!(r"^/?hab/pkgs/([^/]+)/([^/]+)/([^/]+)/([^/]+)/{}$", MetaFile::Target)).unwrap());
        map
    };
}

type Metadata = HashMap<MetaFile, String>;

#[derive(Debug)]
pub struct PackageArchive {
    pub path: PathBuf,
    metadata: Option<Metadata>,
}

impl PackageArchive {
    pub fn new<P: Into<PathBuf>>(path: P) -> Self {
        PackageArchive {
            path: path.into(),
            metadata: None,
        }
    }

    /// Calculate and return the checksum of the package archive in base64 format.
    ///
    /// # Failures
    ///
    /// * If the archive cannot be read
    pub fn checksum(&self) -> Result<String> {
        hash::hash_file(&self.path)
    }

    pub fn cflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::CFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn config(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Config) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    /// Returns a list of package identifiers representing the runtime package dependencies for
    /// this archive.
    ///
    /// # Failures
    ///
    /// * If a `DEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn deps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::Deps)
    }

    /// Returns a list of package identifiers representing the transitive runtime package
    /// dependencies for this archive.
    ///
    /// # Failures
    ///
    /// * If a `TDEPS` metafile is not found in the archive
    /// * If the archive cannot be read
    /// * If the archive cannot be verified
    pub fn tdeps(&mut self) -> Result<Vec<PackageIdent>> {
        self.read_deps(MetaFile::TDeps)
    }

    pub fn exposes(&mut self) -> Result<Vec<u16>> {
        match self.read_metadata(MetaFile::Exposes) {
            Ok(Some(data)) => {
                let ports: Vec<u16> = data.split(" ")
                    .filter_map(|port| port.parse::<u16>().ok())
                    .collect();
                Ok(ports)
            }
            Ok(None) => Ok(vec![]),
            Err(e) => Err(e),
        }
    }

    pub fn ident(&mut self) -> Result<PackageIdent> {
        match self.read_metadata(MetaFile::Ident) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Ident)),
            Ok(Some(data)) => PackageIdent::from_str(&data),
            Err(e) => Err(e),
        }
    }

    pub fn ld_run_path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdRunPath) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn ldflags(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::LdFlags) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn manifest(&mut self) -> Result<String> {
        match self.read_metadata(MetaFile::Manifest) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Manifest)),
            Ok(Some(data)) => Ok(data.clone()),
            Err(e) => Err(e),
        }
    }

    pub fn path(&mut self) -> Result<Option<String>> {
        match self.read_metadata(MetaFile::Path) {
            Ok(data) => Ok(data.cloned()),
            Err(e) => Err(e),
        }
    }

    pub fn target(&mut self) -> Result<PackageTarget> {
        match self.read_metadata(MetaFile::Target) {
            Ok(None) => Err(Error::MetaFileNotFound(MetaFile::Target)),
            Ok(Some(data)) => PackageTarget::from_str(&data),
            Err(e) => Err(e),
        }
    }

    /// A plain string representation of the archive's file name.
    pub fn file_name(&self) -> String {
        self.path.file_name().unwrap().to_string_lossy().into_owned()
    }

    /// Given a package name and a path to a file as an `&str`, verify
    /// the files signature.
    ///
    /// # Failures
    ///
    /// * Fails if it cannot verify the signature for any reason
    pub fn verify<P: AsRef<Path>>(&self, cache_key_path: &P) -> Result<(String, String)> {
        artifact::verify(&self.path, cache_key_path)
    }

    /// Given a package name and a path to a file as an `&str`, unpack
    /// the package.
    ///
    /// # Failures
    ///
    /// * If the package cannot be unpacked
    pub fn unpack(&self, fs_root_path: Option<&Path>) -> Result<()> {
        let root = fs_root_path.unwrap_or(Path::new("/"));
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        let writer = writer::Disk::new();
        let mut extract_options = ExtractOptions::new();
        extract_options.add(ExtractOption::Time);
        extract_options.add(ExtractOption::Owner);
        extract_options.add(ExtractOption::Permissions);
        try!(writer.set_options(&extract_options));
        try!(writer.set_standard_lookup());
        try!(writer.write(&mut reader, Some(root.to_string_lossy().as_ref())));
        try!(writer.close());
        Ok(())
    }

    fn read_deps(&mut self, file: MetaFile) -> Result<Vec<PackageIdent>> {
        let mut deps: Vec<PackageIdent> = vec![];
        let filename = format!("{}", &file);
        match self.read_metadata(file) {
            Ok(Some(body)) => {
                debug!("body {} = [{}]", &filename, &body);
                let ids: Vec<String> = body.lines().map(|d| d.to_string()).collect();
                for id in &ids {
                    debug!("id {} = [{}]", &filename, &id);
                    let package = try!(PackageIdent::from_str(id));
                    if !package.fully_qualified() {
                        // JW TODO: use a more appropriate erorr to describe the invalid
                        // user input here. (user because a package was generated by a user
                        // and read into program)
                        return Err(Error::InvalidPackageIdent(package.to_string()));
                    }
                    deps.push(package);
                }
                Ok(deps)
            }
            Ok(None) => Ok(vec![]),
            Err(Error::MetaFileNotFound(_)) => Ok(deps),
            Err(e) => Err(e),
        }
    }

    fn read_metadata(&mut self, file: MetaFile) -> Result<Option<&String>> {
        if let Some(ref files) = self.metadata {
            return Ok(files.get(&file));
        }
        let mut metadata = Metadata::new();
        let mut matched_count = 0u8;
        let tar_reader = try!(artifact::get_archive_reader(&self.path));
        let mut builder = reader::Builder::new();
        try!(builder.support_format(ReadFormat::Gnutar));
        try!(builder.support_filter(ReadFilter::Xz));
        let mut reader = try!(builder.open_stream(tar_reader));
        loop {
            let mut matched_type: Option<MetaFile> = None;
            if let Some(entry) = reader.next_header() {
                for (matched, regx) in METAFILE_REGXS.iter() {
                    if regx.is_match(entry.pathname()) {
                        matched_type = Some((*matched).clone());
                        matched_count += 1;
                        break;
                    }
                }
            } else {
                break;
            }

            if matched_type.is_none() {
                continue;
            }

            let mut buf = String::new();
            loop {
                match reader.read_block() {
                    Ok(Some(bytes)) => {
                        match str::from_utf8(bytes) {
                            Ok(content) => {
                                // You used to trim. Now you don't, because you were trimming
                                // in the wrong place. Sometimes a buffer ends (or starts!) with
                                // a newline.
                                buf.push_str(content);
                            }
                            Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                        }
                    }
                    Ok(None) => {
                        debug!("content = {}", &buf);
                        // Hey, before you go - we are trimming whitespace for you. This
                        // is handy, because later on, you just want the string you want.
                        metadata.insert(matched_type.unwrap(), String::from(buf.trim()));
                        break;
                    }
                    Err(_) => return Err(Error::MetaFileMalformed(matched_type.unwrap())),
                }
            }//inner loop

            if matched_count == METAFILE_REGXS.len() as u8 {
                break;
            }
        }
        self.metadata = Some(metadata);
        Ok(self.metadata.as_ref().unwrap().get(&file))
    }
}

pub trait FromArchive: Sized {
    type Error: error::Error;

    fn from_archive(archive: &mut PackageArchive) -> result::Result<Self, Self::Error>;
}

#[cfg(test)]
mod test {
    use std::path::PathBuf;
    use os::system::{Architecture, Platform};
    use super::*;

    #[test]
    fn reading_artifact_metadata() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let ident = hart.ident().unwrap();
        assert_eq!(ident.origin, "happyhumans");
        assert_eq!(ident.name, "possums");
        assert_eq!(ident.version, Some("8.1.4".to_string()));
        assert_eq!(ident.release, Some("20160427165340".to_string()));
    }

    pub fn root() -> PathBuf {
        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests")
    }

    pub fn fixtures() -> PathBuf {
        root().join("fixtures")
    }

    #[test]
    fn reading_artifact_deps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("happyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let _ = hart.deps().unwrap();
        let _ = hart.tdeps().unwrap();
    }

    #[test]
    fn reading_artifact_large_tdeps() {
        let mut hart = PackageArchive::new(fixtures()
            .join("unhappyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let tdeps = hart.tdeps().unwrap();
        assert_eq!(1024, tdeps.len());
    }

    #[test]
    fn reading_artifact_target() {
        let mut hart = PackageArchive::new(fixtures()
            .join("unhappyhumans-possums-8.1.4-20160427165340-x86_64-linux.hart"));
        let target = hart.target().unwrap();
        assert_eq!(target.platform, Platform::Linux);
        assert_eq!(target.architecture, Architecture::X86_64);
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::ArrayBase;
use ndarray::blas::AsBlas;
use ndarray::blas;

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

// TODO Dimension type alias
// TODO OwnedArray

pub struct OrthogonalNMFBlas<FloatT> {
    pub hidden: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights: ArrayBase<Vec<FloatT>, (usize, usize)>,

    // these hold temporary results during an iteration.
    // kept in struct to prevent unnecessary memory allocations.
    pub tmp_weights_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub tmp_weights_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub tmp_weights_divisor_reconstruction: ArrayBase<Vec<FloatT>, (usize, usize)>,
    //
    // pub tmp_hidden_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub tmp_hidden_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    // pub tmp_hidden_divisor_tmp: ArrayBase<Vec<FloatT>, (usize, usize)>,
}

impl<FloatT> OrthogonalNMFBlas<FloatT>
    where FloatT: Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: Matrix,
          // ndarray::blas::BlasArrayViewMut
          Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas<FloatT> {
        let mut hidden = ArrayBase::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = ArrayBase::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: ArrayBase<Vec<FloatT>, (usize, usize)>, weights: ArrayBase<Vec<FloatT>, (usize, usize)>) -> OrthogonalNMFBlas<FloatT> {
        let weights_shape = weights.shape_as_tuple();
        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,
            tmp_weights_dividend: ArrayBase::zeros(weights_shape),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    // TODO samples_shape ?
}

impl OrthogonalNMFBlas<f64> {
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: f64, samples: &mut ArrayBase<Vec<f64>, (usize, usize)>) {
        assert_eq!(samples.shape_as_tuple(), (self.nsamples(), self.nobserved()));

        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.tmp_weights_dividend.blas());
//
//         // has the same shape as weights
//         let new_weights_dividend = data.clone().mul(&hidden_transposed);
//         // has the same shape as weights
//         let new_weights_divisor = self.weights.clone().mul(&self.hidden).mul(&hidden_transposed);
//
//         // has the same shape as hidden
//         let new_hidden_dividend = weights_transposed.clone().mul(data);
//
//         // gamma is a symetric matrix with diagonal elements equal to zero
//         // and other elements = alpha
//         let gamma_size = self.nhidden();
//         let mut gamma = DMat::from_elem(gamma_size, gamma_size, alpha);
//
//         // set diagonal to zero
//         for i in 0..gamma_size {
//             gamma[(i, i)] = FloatT::zero();
//         }
//
//         // has the same shape as hidden
//         let new_hidden_divisor = weights_transposed.clone()
//             .mul(&self.weights)
//             .mul(&self.hidden)
//             // we add the previous latents
//             // multiplied by alpha except for the diag which is set to zero
//             .add(gamma.mul(&self.hidden));
//
//         // compute new weights
//         // TODO possibly use simd for this
//         for col in 0..self.weights.ncols() {
//             for row in 0..self.weights.nrows() {
//                 let index = (row, col);
//                 // if we have any zero in any of the matrizes
//                 // self.weights or self.hidden then
//                 // new_weights_divisor[index] will be zero
//                 // TODO how to deal with this
//                 let mut divisor = new_weights_divisor[index];
//                 if FloatT::zero() == divisor {
//                     divisor = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != divisor);
//                 self.weights[index] =
//                     self.weights[index] *
//                     new_weights_dividend[index] /
//                     divisor;
//                 if FloatT::zero() == self.weights[index] {
//                     self.weights[index] = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != self.weights[index]);
//             }
//         }
//
//         // compute new hidden
//         // TODO possibly use simd for this
//         for col in 0..self.hidden.ncols() {
//             for row in 0..self.hidden.nrows() {
//                 let index = (row, col);
//                 let mut divisor = new_hidden_divisor[index];
//                 if FloatT::zero() == divisor {
//                     divisor = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != divisor);
//                 self.hidden[index] =
//                     self.hidden[index] *
//                     new_hidden_dividend[index] /
//                     divisor;
//                 if FloatT::zero() == self.hidden[index] {
//                     self.hidden[index] = FloatT::min_positive_value();
//                 }
//                 debug_assert!(FloatT::zero() != self.hidden[index]);
//             }
//         }
    }
}
<commit_msg>ortho nmf blas: almost done but not generic<commit_after>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f64;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

// TODO Dimension type alias
// TODO OwnedArray

pub struct OrthogonalNMFBlas {
    pub hidden: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub weights: ArrayBase<Vec<FloatT>, (usize, usize)>,

    // these hold temporary results during an iteration.
    // kept in struct to prevent unnecessary memory allocations.
    // TODO dont call these tmp
    pub tmp_weights_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub tmp_weights_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub tmp_weights_divisor_reconstruction: ArrayBase<Vec<FloatT>, (usize, usize)>,

    pub tmp_hidden_dividend: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub tmp_hidden_divisor: ArrayBase<Vec<FloatT>, (usize, usize)>,
    pub tmp_hidden_divisor_partial: ArrayBase<Vec<FloatT>, (usize, usize)>,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    pub fn init_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = ArrayBase::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = ArrayBase::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::init(hidden, weights)
    }

    // TODO initialize with values from last time step t-1 instead of choosing randomly
    pub fn init(hidden: ArrayBase<Vec<FloatT>, (usize, usize)>, weights: ArrayBase<Vec<FloatT>, (usize, usize)>) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,
            tmp_weights_dividend: ArrayBase::zeros(weights_shape),
            tmp_weights_divisor: ArrayBase::zeros(weights_shape),
            tmp_weights_divisor_reconstruction: ArrayBase::zeros(samples_shape),
            tmp_hidden_dividend: ArrayBase::zeros(hidden_shape),
            tmp_hidden_divisor: ArrayBase::zeros(hidden_shape),
            tmp_hidden_divisor_partial: ArrayBase::zeros((nhidden, nhidden)),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    #[inline]
    pub fn iterate_weights_dividend(&mut self, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.tmp_weights_dividend.blas());

    }

    // TODO docstring
    #[inline]
    pub fn iterate_weights_divisor(&mut self) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.tmp_weights_divisor_reconstruction.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.tmp_weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.tmp_weights_divisor.blas());
    }

    #[inline]
    pub fn iterate_hidden_dividend(&mut self, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.tmp_hidden_dividend.blas());
    }

    #[inline]
    pub fn iterate_hidden_divisor(&mut self, alpha: FloatT, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        // // gamma is a symetric matrix with diagonal elements equal to zero
        // // and other elements = alpha
        // let gamma_size = self.nhidden();
        // let mut gamma = DMat::from_elem(gamma_size, gamma_size, alpha);
        //
        // // set diagonal to zero
        // for i in 0..gamma_size {
        //     gamma[(i, i)] = FloatT::zero();
        // }
    }

    // TODO better name
    // per element division
    #[inline]
    pub fn update(
        dividend: &ArrayBase<Vec<FloatT>, (usize, usize)>,
        divisor: &ArrayBase<Vec<FloatT>, (usize, usize)>,
        result: &mut ArrayBase<Vec<FloatT>, (usize, usize)>,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, dividend.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any zero in any of the matrizes
                // self.weights or self.hidden then
                // divisor will be zero.
                // we can't divide by zero
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= dividend.uget(index) / div;
                }
                // TODO maybe also zero adjust the final weight
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// it gets better and better with each iteration.
    /// one observed per column.
    /// one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut ArrayBase<Vec<FloatT>, (usize, usize)>) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        // TODO benchmark these individually
        // TODO add little descriptions like
        // X <- X^T
        // TODO also add them to docstrings
        // TODO maybe pass in all data explicitely
        self.iterate_weights_dividend(samples);
        self.iterate_weights_divisor();
        self.iterate_hidden_dividend(samples);
        self.iterate_hidden_divisor(alpha, samples);

        OrthogonalNMFBlas::update(
            &self.tmp_weights_dividend,
            &self.tmp_weights_divisor,
            &mut self.weights);
        OrthogonalNMFBlas::update(
            &self.tmp_hidden_dividend,
            &self.tmp_hidden_divisor,
            &mut self.hidden);
    }
}
<|endoftext|>


<commit_before>use core::intrinsics::{atomic_xadd, atomic_xsub, breakpoint, volatile_load, volatile_store};
use core::mem;
use core::raw;

use common::{RingBuffer, Queue};

#[allow(improper_ctypes)]
extern {
    pub fn switch_to_user(user_stack: *mut u8, mem_base: *mut u8) -> *mut u8;
}

/// Size of each processes's memory region in bytes
pub const PROC_MEMORY_SIZE : usize = 8192;
pub const NUM_PROCS : usize = 1;

static mut FREE_MEMORY_IDX: usize = 0;

#[link_section = ".app_memory"]
static mut MEMORIES: [[u8; PROC_MEMORY_SIZE]; NUM_PROCS] = [[0; PROC_MEMORY_SIZE]; NUM_PROCS];

pub static mut PROCS : [Option<Process<'static>>; NUM_PROCS] = [None];

pub fn schedule(callback: Callback, appid: ::AppId) -> bool {
    let procs = unsafe { &mut PROCS };
    let idx = appid.idx();
    if idx >= procs.len() {
        return false
    }

    match procs[idx] {
        None => false,
        Some(ref mut p) => {
            // TODO(alevy): validate appid liveness
            p.callbacks.enqueue(callback)
        }
    }
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum State {
    Running,
    Waiting
}

#[derive(Copy,Clone)]
pub struct Callback {
    pub r0: usize,
    pub r1: usize,
    pub r2: usize,
    pub r3: usize,
    pub pc: usize
}

#[repr(C,packed)]
struct LoadInfo {
    entry_loc: usize,        /* Entry point for user application */
    init_data_loc: usize,    /* Data initialization information in flash */
    init_data_size: usize,    /* Size of initialization information */
    got_start_offset: usize,  /* Offset to start of GOT */
    got_end_offset: usize,    /* Offset to end of GOT */
    bss_start_offset: usize,  /* Offset to start of BSS */
    bss_end_offset: usize    /* Offset to end of BSS */
}

pub struct Process<'a> {
    /// The process's memory.
    memory: &'a mut [u8],

    exposed_memory_start: *mut u8,

    /// The offset in `memory` to use for the process stack.
    cur_stack: *mut u8,

    wait_pc: usize,

    pub state: State,

    pub callbacks: RingBuffer<'a, Callback>
}

impl<'a> Process<'a> {
    #[inline(never)]
    pub unsafe fn create(start_addr: *const usize) -> Option<Process<'a>> {
        let cur_idx = atomic_xadd(&mut FREE_MEMORY_IDX, 1);
        if cur_idx > MEMORIES.len() {
            atomic_xsub(&mut FREE_MEMORY_IDX, 1);
            None
        } else {
            let memory = &mut MEMORIES[cur_idx];

            let stack_bottom = &mut memory[PROC_MEMORY_SIZE - 4] as *mut u8;

            // Take callback buffer from bottom of process memory
            let callback_len = 10;
            let callback_buf = mem::transmute(raw::Slice {
                data: &mut memory[0] as *mut u8 as *mut Option<Callback>,
                len: callback_len
            });
            let callback_size = mem::size_of::<Option<Callback>>();

            let callbacks = RingBuffer::new(callback_buf);

            let exposed_memory_start =
                    &mut memory[callback_len * callback_size] as *mut u8;

            let mut result = Process {
                memory: memory,
                exposed_memory_start: exposed_memory_start,
                cur_stack: stack_bottom as *mut u8,
                wait_pc: 0,
                state: State::Waiting,
                callbacks: callbacks
            };

            result.load(start_addr);

            Some(result)
        }
    }

    unsafe fn load(&mut self, start_addr: *const usize) {
        let load_info : &LoadInfo = mem::transmute(start_addr);
        let exposed_memory_start = self.exposed_memory_start;

        // Zero out BSS
        ::core::intrinsics::write_bytes(
            exposed_memory_start.offset(load_info.bss_start_offset as isize),
            0,
            load_info.bss_end_offset - load_info.bss_start_offset);

        // Copy data into Data section
        let init_data : &[u8] = mem::transmute(raw::Slice{
            data: (load_info.init_data_loc + start_addr as usize) as *mut u8,
            len: load_info.init_data_size
        });

        let target_data : &mut [u8] = mem::transmute(raw::Slice{
            data: exposed_memory_start,
            len: load_info.init_data_size
        });

        target_data.clone_from_slice(init_data);

        // Fixup Global Offset Table
        let mut got_cur = exposed_memory_start.offset(load_info.got_start_offset as isize) as *mut usize;
        let got_end = exposed_memory_start.offset(load_info.got_end_offset as isize) as *mut usize;
        while got_cur != got_end {
            let entry = *got_cur;
            if (entry & 0x80000000) == 0 {
                // Regular data (memory relative)
                *got_cur = entry + (exposed_memory_start as usize);
            } else {
                // rodata or function pointer (code relative)
                *got_cur = (entry ^ 0x80000000) + (start_addr as usize);
            }
            got_cur = got_cur.offset(1);
        }

        // Entry point is offset from app code
        let init_fn = start_addr as usize + load_info.entry_loc;

        let heap_start = exposed_memory_start.offset(load_info.init_data_size as isize);

        self.callbacks.enqueue(Callback {
            pc: init_fn as usize,
            r0: heap_start as usize,
            r1: 0,
            r2: 0,
            r3: 0
        });
    }

    pub fn in_exposed_bounds(&self, buf_start_addr: *const u8, size: usize)
            -> bool {
        use core::raw::Repr;

        let buf_end_addr = ((buf_start_addr as usize) + size) as *const u8;

        let mem = self.memory.repr();
        let mem_end = ((mem.data as usize) + mem.len) as *const u8;

        buf_start_addr >= self.exposed_memory_start && buf_end_addr <= mem_end
    }

    pub unsafe fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
        use core::raw::Slice;

        let mem_len = self.memory.len();
        let end_mem = &mut self.memory[mem_len - 1] as *mut u8;
        let new_start = self.exposed_memory_start.offset(size as isize);
        if new_start >= end_mem {
            None
        } else {
            let buf = Slice {
                data: self.exposed_memory_start,
                len: size
            };
            self.exposed_memory_start = new_start;
            Some(mem::transmute(buf))
        }
    }

    pub unsafe fn free<T>(&mut self, _: *mut T) {}

    pub fn pop_syscall_stack(&mut self) {
        let pspr = self.cur_stack as *const usize;
        unsafe {
            self.wait_pc = volatile_load(pspr.offset(6));
            self.cur_stack =
                (self.cur_stack as *mut usize).offset(8) as *mut u8;
        }
    }

    /// Context switch to the process.
    pub unsafe fn switch_to_callback(&mut self, callback: Callback) {
        // Fill in initial stack expected by SVC handler
        // Top minus 8 u32s for r0-r3, r12, lr, pc and xPSR
        let stack_bottom = (self.cur_stack as *mut usize).offset(-8);
        volatile_store(stack_bottom.offset(7), 0x01000000);
        volatile_store(stack_bottom.offset(6), callback.pc | 1);
        // Set the LR register to the saved PC so the callback returns to
        // wherever wait was called. Set lowest bit to one because of THUMB
        // instruction requirements.
        volatile_store(stack_bottom.offset(5), self.wait_pc | 0x1);
        volatile_store(stack_bottom, callback.r0);
        volatile_store(stack_bottom.offset(1), callback.r1);
        volatile_store(stack_bottom.offset(2), callback.r2);
        volatile_store(stack_bottom.offset(3), callback.r3);

        self.cur_stack = stack_bottom as *mut u8;
        self.switch_to();
    }

    /// Context switch to the process.
    pub unsafe fn switch_to(&mut self) {
        if self.cur_stack < self.exposed_memory_start {
            breakpoint();
        }
        let psp = switch_to_user(self.cur_stack, self.exposed_memory_start);
        self.cur_stack = psp;
    }

    pub fn svc_number(&self) -> Option<u8> {
        let psp = self.cur_stack as *const *const u16;
        unsafe {
            let pcptr = volatile_load((psp as *const *const u16).offset(6));
            let svc_instr = volatile_load(pcptr.offset(-1));
            Some((svc_instr & 0xff) as u8)
        }
    }

    pub fn lr(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(5)) }
    }

    pub fn r0(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr) }
    }

    pub fn set_r0(&mut self, val: isize) {
        let pspr = self.cur_stack as *mut isize;
        unsafe { volatile_store(pspr, val) }
    }

    pub fn r1(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(1)) }
    }

    pub fn r2(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(2)) }
    }

    pub fn r3(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(3)) }
    }

}

<commit_msg>WORKAROUND: Decrease process memory to 4K<commit_after>use core::intrinsics::{atomic_xadd, atomic_xsub, breakpoint, volatile_load, volatile_store};
use core::mem;
use core::raw;

use common::{RingBuffer, Queue};

#[allow(improper_ctypes)]
extern {
    pub fn switch_to_user(user_stack: *mut u8, mem_base: *mut u8) -> *mut u8;
}

/// Size of each processes's memory region in bytes
pub const PROC_MEMORY_SIZE : usize = 4096;
pub const NUM_PROCS : usize = 1;

static mut FREE_MEMORY_IDX: usize = 0;

#[link_section = ".app_memory"]
static mut MEMORIES: [[u8; PROC_MEMORY_SIZE]; NUM_PROCS] = [[0; PROC_MEMORY_SIZE]; NUM_PROCS];

pub static mut PROCS : [Option<Process<'static>>; NUM_PROCS] = [None];

pub fn schedule(callback: Callback, appid: ::AppId) -> bool {
    let procs = unsafe { &mut PROCS };
    let idx = appid.idx();
    if idx >= procs.len() {
        return false
    }

    match procs[idx] {
        None => false,
        Some(ref mut p) => {
            // TODO(alevy): validate appid liveness
            p.callbacks.enqueue(callback)
        }
    }
}

#[derive(Copy,Clone,PartialEq,Eq)]
pub enum State {
    Running,
    Waiting
}

#[derive(Copy,Clone)]
pub struct Callback {
    pub r0: usize,
    pub r1: usize,
    pub r2: usize,
    pub r3: usize,
    pub pc: usize
}

#[repr(C,packed)]
struct LoadInfo {
    entry_loc: usize,        /* Entry point for user application */
    init_data_loc: usize,    /* Data initialization information in flash */
    init_data_size: usize,    /* Size of initialization information */
    got_start_offset: usize,  /* Offset to start of GOT */
    got_end_offset: usize,    /* Offset to end of GOT */
    bss_start_offset: usize,  /* Offset to start of BSS */
    bss_end_offset: usize    /* Offset to end of BSS */
}

pub struct Process<'a> {
    /// The process's memory.
    memory: &'a mut [u8],

    exposed_memory_start: *mut u8,

    /// The offset in `memory` to use for the process stack.
    cur_stack: *mut u8,

    wait_pc: usize,

    pub state: State,

    pub callbacks: RingBuffer<'a, Callback>
}

impl<'a> Process<'a> {
    #[inline(never)]
    pub unsafe fn create(start_addr: *const usize) -> Option<Process<'a>> {
        let cur_idx = atomic_xadd(&mut FREE_MEMORY_IDX, 1);
        if cur_idx > MEMORIES.len() {
            atomic_xsub(&mut FREE_MEMORY_IDX, 1);
            None
        } else {
            let memory = &mut MEMORIES[cur_idx];

            let stack_bottom = &mut memory[PROC_MEMORY_SIZE - 4] as *mut u8;

            // Take callback buffer from bottom of process memory
            let callback_len = 10;
            let callback_buf = mem::transmute(raw::Slice {
                data: &mut memory[0] as *mut u8 as *mut Option<Callback>,
                len: callback_len
            });
            let callback_size = mem::size_of::<Option<Callback>>();

            let callbacks = RingBuffer::new(callback_buf);

            let exposed_memory_start =
                    &mut memory[callback_len * callback_size] as *mut u8;

            let mut result = Process {
                memory: memory,
                exposed_memory_start: exposed_memory_start,
                cur_stack: stack_bottom as *mut u8,
                wait_pc: 0,
                state: State::Waiting,
                callbacks: callbacks
            };

            result.load(start_addr);

            Some(result)
        }
    }

    unsafe fn load(&mut self, start_addr: *const usize) {
        let load_info : &LoadInfo = mem::transmute(start_addr);
        let exposed_memory_start = self.exposed_memory_start;

        // Zero out BSS
        ::core::intrinsics::write_bytes(
            exposed_memory_start.offset(load_info.bss_start_offset as isize),
            0,
            load_info.bss_end_offset - load_info.bss_start_offset);

        // Copy data into Data section
        let init_data : &[u8] = mem::transmute(raw::Slice{
            data: (load_info.init_data_loc + start_addr as usize) as *mut u8,
            len: load_info.init_data_size
        });

        let target_data : &mut [u8] = mem::transmute(raw::Slice{
            data: exposed_memory_start,
            len: load_info.init_data_size
        });

        target_data.clone_from_slice(init_data);

        // Fixup Global Offset Table
        let mut got_cur = exposed_memory_start.offset(load_info.got_start_offset as isize) as *mut usize;
        let got_end = exposed_memory_start.offset(load_info.got_end_offset as isize) as *mut usize;
        while got_cur != got_end {
            let entry = *got_cur;
            if (entry & 0x80000000) == 0 {
                // Regular data (memory relative)
                *got_cur = entry + (exposed_memory_start as usize);
            } else {
                // rodata or function pointer (code relative)
                *got_cur = (entry ^ 0x80000000) + (start_addr as usize);
            }
            got_cur = got_cur.offset(1);
        }

        // Entry point is offset from app code
        let init_fn = start_addr as usize + load_info.entry_loc;

        let heap_start = exposed_memory_start.offset(load_info.init_data_size as isize);

        self.callbacks.enqueue(Callback {
            pc: init_fn as usize,
            r0: heap_start as usize,
            r1: 0,
            r2: 0,
            r3: 0
        });
    }

    pub fn in_exposed_bounds(&self, buf_start_addr: *const u8, size: usize)
            -> bool {
        use core::raw::Repr;

        let buf_end_addr = ((buf_start_addr as usize) + size) as *const u8;

        let mem = self.memory.repr();
        let mem_end = ((mem.data as usize) + mem.len) as *const u8;

        buf_start_addr >= self.exposed_memory_start && buf_end_addr <= mem_end
    }

    pub unsafe fn alloc(&mut self, size: usize) -> Option<&mut [u8]> {
        use core::raw::Slice;

        let mem_len = self.memory.len();
        let end_mem = &mut self.memory[mem_len - 1] as *mut u8;
        let new_start = self.exposed_memory_start.offset(size as isize);
        if new_start >= end_mem {
            None
        } else {
            let buf = Slice {
                data: self.exposed_memory_start,
                len: size
            };
            self.exposed_memory_start = new_start;
            Some(mem::transmute(buf))
        }
    }

    pub unsafe fn free<T>(&mut self, _: *mut T) {}

    pub fn pop_syscall_stack(&mut self) {
        let pspr = self.cur_stack as *const usize;
        unsafe {
            self.wait_pc = volatile_load(pspr.offset(6));
            self.cur_stack =
                (self.cur_stack as *mut usize).offset(8) as *mut u8;
        }
    }

    /// Context switch to the process.
    pub unsafe fn switch_to_callback(&mut self, callback: Callback) {
        // Fill in initial stack expected by SVC handler
        // Top minus 8 u32s for r0-r3, r12, lr, pc and xPSR
        let stack_bottom = (self.cur_stack as *mut usize).offset(-8);
        volatile_store(stack_bottom.offset(7), 0x01000000);
        volatile_store(stack_bottom.offset(6), callback.pc | 1);
        // Set the LR register to the saved PC so the callback returns to
        // wherever wait was called. Set lowest bit to one because of THUMB
        // instruction requirements.
        volatile_store(stack_bottom.offset(5), self.wait_pc | 0x1);
        volatile_store(stack_bottom, callback.r0);
        volatile_store(stack_bottom.offset(1), callback.r1);
        volatile_store(stack_bottom.offset(2), callback.r2);
        volatile_store(stack_bottom.offset(3), callback.r3);

        self.cur_stack = stack_bottom as *mut u8;
        self.switch_to();
    }

    /// Context switch to the process.
    pub unsafe fn switch_to(&mut self) {
        if self.cur_stack < self.exposed_memory_start {
            breakpoint();
        }
        let psp = switch_to_user(self.cur_stack, self.exposed_memory_start);
        self.cur_stack = psp;
    }

    pub fn svc_number(&self) -> Option<u8> {
        let psp = self.cur_stack as *const *const u16;
        unsafe {
            let pcptr = volatile_load((psp as *const *const u16).offset(6));
            let svc_instr = volatile_load(pcptr.offset(-1));
            Some((svc_instr & 0xff) as u8)
        }
    }

    pub fn lr(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(5)) }
    }

    pub fn r0(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr) }
    }

    pub fn set_r0(&mut self, val: isize) {
        let pspr = self.cur_stack as *mut isize;
        unsafe { volatile_store(pspr, val) }
    }

    pub fn r1(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(1)) }
    }

    pub fn r2(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(2)) }
    }

    pub fn r3(&self) -> usize {
        let pspr = self.cur_stack as *const usize;
        unsafe { volatile_load(pspr.offset(3)) }
    }

}

<|endoftext|>


<commit_before>use uuid::Uuid;

pub struct Packet {
    id: i32,
    data: Vec<Field>
}
enum Field {
    Boolean(bool),
    Byte(i8),
    UByte(u8),
    Short(i16),
    UShort(i16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    String(String),
    Chat(String),
    VarInt(i32),
    VarLong(i32),
    //TODO: Chunk, Entity meta, slot, nbt, byte array, optx, array optx...
    Position { x: i32, y: i16, z: i32 },
    Angle(i8),
    UUID(Uuid)
}

pub enum PacketType {
    PlayIn(PlayIn),
    PlayOut(PlayOut),
    StatusIn(StatusIn),
    StatusOut(StatusOut)
}

/// Server -> Client (Play)
pub enum PlayIn {
    SpawnObject = 0x00,
    SpawnExpOrb = 0x01,
    SpawnGlobalEntity = 0x02,
    SpawnMob = 0x03,
    SpawnPainting = 0x04,
    SpawnPlayer = 0x05,
    Animation = 0x06,
    Statistics = 0x07,
    BlockBreakAnimation = 0x08,
    UpdateBlockEntity = 0x09,
    BlockAction = 0x0A,
    BlockChange = 0x0B,
    BossBar = 0x0C,
    ServerDifficulty = 0x0D,
    TabComplete = 0x0E,
    ChatMessage = 0x0F,
    MultiBlockChange = 0x10,
    ConfirmTransaction = 0x11,
    CloseWindow = 0x12,
    OpenWindow = 0x13,
    WindowItems = 0x14,
    WindowProperty = 0x15,
    SetSlot = 0x16,
    SetCooldown = 0x17,
    PluginMessage = 0x18,
    NamedSoundEffect = 0x19,
    Disconnect = 0x1A,
    EntityStatus = 0x1B,
    Explosion = 0x1C,
    UnloadChunk = 0x1D,
    ChangeGameState = 0x1E,
    KeepAlive = 0x1F,
    ChunkData = 0x20,
    Effect = 0x21,
    Particle = 0x22,
    JoinGame = 0x23,
    Map = 0x24,
    EntityRelativeMove = 0x25,
    EntityLookRelativeMove = 0x26,
    EntityLook = 0x27,
    Entity = 0x28,
    VehicleMove = 0x29,
    OpenSignEditor = 0x2A,
    PlayerAbilities = 0x2B,
    CombatEvent = 0x2C,
    PlayerListItem = 0x2D,
    PlayerPositionLook = 0x2E,
    UseBed = 0x2F,
    DestroyEntities = 0x30,
    RemoveEntityEffect = 0x31,
    ResourcePackSend = 0x32,
    Respawn = 0x33,
    EntityHeadLook = 0x34,
    WorldBorder = 0x35,
    Camera = 0x36,
    HeldItemChange = 0x37,
    DisplayScoreboard = 0x38,
    EntityMetadata = 0x39,
    AttachEntity = 0x3A,
    EntityVelocity = 0x3B,
    EntityEquipment = 0x3C,
    SetExp = 0x3D,
    UpdateHealth = 0x3E,
    ScoreboardObjective = 0x3F,
    SetPassengers = 0x40,
    Teams = 0x41,
    UpdateScore = 0x42,
    SpawnPosition = 0x43,
    TimeUpdate = 0x44,
    Title = 0x45,
    SoundEffect = 0x46,
    PlayerListHeaderFooter = 0x47,
    CollectItem = 0x48,
    EntityTeleport = 0x49,
    EntityProperties = 0x4A,
    EntityEffect = 0x4B
}

/// Client -> Server (Play)
pub enum PlayOut {
    TeleportConfirm = 0x00,
    TabComplete = 0x01,
    ChatMessage = 0x02,
    ClientStatus = 0x03,
    ClientSettings = 0x04,
    ConfirmTransaction = 0x05,
    EnchantItem = 0x06,
    ClickWindow = 0x07,
    CloseWindow = 0x08,
    PluginMessage = 0x09,
    UseEntity = 0x0A,
    KeepAlive = 0x0B,
    PlayerPosition = 0x0C,
    PlayerPositionLook = 0x0D,
    PlayerLook = 0x0E,
    Player = 0x0F,
    VehicleMove = 0x10,
    SteerBoat = 0x11,
    PlayerAbilities = 0x12,
    PlayerDigging = 0x13,
    EntityAction = 0x14,
    SteerVehicle = 0x15,
    ResourcePackStatus = 0x16,
    HeldItemChange = 0x17,
    CreativeInventoryAction = 0x18,
    UpdateSign = 0x19,
    Animation = 0x1A,
    Spectate = 0x1B,
    PlayerBlockPlacement = 0x1C,
    UseItem = 0x1D
}

/// Server -> Client (Status)
pub enum StatusIn {
    Response = 0x00,
    Pong = 0x01
}

/// Client -> Server (Status)
pub enum StatusOut {
    Request = 0x00,
    Ping = 0x01
}

impl Packet {
    /// Create a new empty packet
    pub fn new(id: i32) -> Packet {
        Packet {
            id: id,
            data: vec![]
        }
    }

    // Decode a byte array into a packet
    //pub fn decode(data: &[u8]) -> Option<Packet> {}

    // Encode the packet into a byte array
    //pub fn encode(&self) -> &[u8] {}

    /// Get data field
    pub fn get_data(&self) -> &[Field] {
        &self.data
    }

    /// Get mutable data field
    pub fn get_data_mut(&mut self) -> &mut [Field] {
        &mut self.data
    }
}
<commit_msg>Adding Handshaking and Login Packets<commit_after>use uuid::Uuid;

pub struct Packet {
    id: i32,
    data: Vec<Field>
}
enum Field {
    Boolean(bool),
    Byte(i8),
    UByte(u8),
    Short(i16),
    UShort(i16),
    Int(i32),
    Long(i64),
    Float(f32),
    Double(f64),
    String(String),
    Chat(String),
    VarInt(i32),
    VarLong(i32),
    //TODO: Chunk, Entity meta, slot, nbt, byte array, optx, array optx...
    Position { x: i32, y: i16, z: i32 },
    Angle(i8),
    UUID(Uuid)
}

pub enum PacketType {
    HandshakingOut(HandshakingOut),
    PlayIn(PlayIn),
    PlayOut(PlayOut),
    StatusIn(StatusIn),
    StatusOut(StatusOut),
    LoginIn(LoginIn),
    LoginOut(LoginOut)
}

/// Client -> Server (Play)
pub enum HandshakingOut {
    Handshake = 0x00,
    LegacyServerListPing = 0xFE
}

/// Server -> Client (Play)
pub enum PlayIn {
    SpawnObject = 0x00,
    SpawnExpOrb = 0x01,
    SpawnGlobalEntity = 0x02,
    SpawnMob = 0x03,
    SpawnPainting = 0x04,
    SpawnPlayer = 0x05,
    Animation = 0x06,
    Statistics = 0x07,
    BlockBreakAnimation = 0x08,
    UpdateBlockEntity = 0x09,
    BlockAction = 0x0A,
    BlockChange = 0x0B,
    BossBar = 0x0C,
    ServerDifficulty = 0x0D,
    TabComplete = 0x0E,
    ChatMessage = 0x0F,
    MultiBlockChange = 0x10,
    ConfirmTransaction = 0x11,
    CloseWindow = 0x12,
    OpenWindow = 0x13,
    WindowItems = 0x14,
    WindowProperty = 0x15,
    SetSlot = 0x16,
    SetCooldown = 0x17,
    PluginMessage = 0x18,
    NamedSoundEffect = 0x19,
    Disconnect = 0x1A,
    EntityStatus = 0x1B,
    Explosion = 0x1C,
    UnloadChunk = 0x1D,
    ChangeGameState = 0x1E,
    KeepAlive = 0x1F,
    ChunkData = 0x20,
    Effect = 0x21,
    Particle = 0x22,
    JoinGame = 0x23,
    Map = 0x24,
    EntityRelativeMove = 0x25,
    EntityLookRelativeMove = 0x26,
    EntityLook = 0x27,
    Entity = 0x28,
    VehicleMove = 0x29,
    OpenSignEditor = 0x2A,
    PlayerAbilities = 0x2B,
    CombatEvent = 0x2C,
    PlayerListItem = 0x2D,
    PlayerPositionLook = 0x2E,
    UseBed = 0x2F,
    DestroyEntities = 0x30,
    RemoveEntityEffect = 0x31,
    ResourcePackSend = 0x32,
    Respawn = 0x33,
    EntityHeadLook = 0x34,
    WorldBorder = 0x35,
    Camera = 0x36,
    HeldItemChange = 0x37,
    DisplayScoreboard = 0x38,
    EntityMetadata = 0x39,
    AttachEntity = 0x3A,
    EntityVelocity = 0x3B,
    EntityEquipment = 0x3C,
    SetExp = 0x3D,
    UpdateHealth = 0x3E,
    ScoreboardObjective = 0x3F,
    SetPassengers = 0x40,
    Teams = 0x41,
    UpdateScore = 0x42,
    SpawnPosition = 0x43,
    TimeUpdate = 0x44,
    Title = 0x45,
    SoundEffect = 0x46,
    PlayerListHeaderFooter = 0x47,
    CollectItem = 0x48,
    EntityTeleport = 0x49,
    EntityProperties = 0x4A,
    EntityEffect = 0x4B
}

/// Client -> Server (Play)
pub enum PlayOut {
    TeleportConfirm = 0x00,
    TabComplete = 0x01,
    ChatMessage = 0x02,
    ClientStatus = 0x03,
    ClientSettings = 0x04,
    ConfirmTransaction = 0x05,
    EnchantItem = 0x06,
    ClickWindow = 0x07,
    CloseWindow = 0x08,
    PluginMessage = 0x09,
    UseEntity = 0x0A,
    KeepAlive = 0x0B,
    PlayerPosition = 0x0C,
    PlayerPositionLook = 0x0D,
    PlayerLook = 0x0E,
    Player = 0x0F,
    VehicleMove = 0x10,
    SteerBoat = 0x11,
    PlayerAbilities = 0x12,
    PlayerDigging = 0x13,
    EntityAction = 0x14,
    SteerVehicle = 0x15,
    ResourcePackStatus = 0x16,
    HeldItemChange = 0x17,
    CreativeInventoryAction = 0x18,
    UpdateSign = 0x19,
    Animation = 0x1A,
    Spectate = 0x1B,
    PlayerBlockPlacement = 0x1C,
    UseItem = 0x1D
}

/// Server -> Client (Status)
pub enum StatusIn {
    Response = 0x00,
    Pong = 0x01
}

/// Client -> Server (Status)
pub enum StatusOut {
    Request = 0x00,
    Ping = 0x01
}

/// Server -> Client (Login)
pub enum LoginIn {
    Disconnect = 0x00,
    EncryptionRequest = 0x01,
    LoginSuccess = 0x02,
    SetCompression = 0x03
}

/// Client -> Server (Login)
pub enum LoginOut {
    LoginStart = 0x00,
    EncryptionResponse = 0x01
}

impl Packet {
    /// Create a new empty packet
    pub fn new(id: i32) -> Packet {
        Packet {
            id: id,
            data: vec![]
        }
    }

    // Decode a byte array into a packet
    //pub fn decode(data: &[u8]) -> Option<Packet> {}

    // Encode the packet into a byte array
    //pub fn encode(&self) -> &[u8] {}

    /// Get data field
    pub fn get_data(&self) -> &[Field] {
        &self.data
    }

    /// Get mutable data field
    pub fn get_data_mut(&mut self) -> &mut [Field] {
        &mut self.data
    }
}
<|endoftext|>