<commit_before>use std::collections::HashSet;

use tx::{self, Transaction};

pub struct ThreadedStaker {
    tx_pool: HashSet<String>
}

// use std::sync::mpsc::{channel, Sender, Receiver};
// struct SimplesService {
//     tx_sender: Sender<simples_pb::Transaction>,
// }

// impl Service for SimplesService {
//     fn pub_transaction(
//         &mut self, request: simples_pb::PublishTransactionRequest) ->
//         SimplesResult<simples_pb::PublishTransactionResponse> {
//             println!("{:?}", request.get_transaction());
//             let response = simples_pb::PublishTransactionResponse::new();
//             Ok(response)
//             // tx_sender.send(msg).unwrap();
//             // let reply = format!("reply");
//         }
// }
<commit_msg>Added support for basic proof-hash manipulation.<commit_after>use std::collections::HashSet;
use std::cmp::{Ordering};
use std::fmt;
use std::num::{UnsignedInt, Int};
use time::now_utc;

use tx::{self, Transaction};
use sodiumoxide::crypto::hash::sha512::{self, Digest, HASHBYTES};

pub struct ProofHash([u8; HASHBYTES]);

impl ProofHash {
    fn from_u64(mut value: u64) -> ProofHash {
        let mut proof_hash = ProofHash([0; HASHBYTES]);
        let mut index = 0us;
        while value > 0u64 {
            proof_hash.0[index] = (value & 0xffu64) as u8;
            value = value >> 8;
            index += 1;
        }
        proof_hash
    }

    fn multiply_in_place(&mut self, other: &ProofHash) {
        let mut quot = 0u16;
        for index in range(0, HASHBYTES) {
            quot = self.0[index] as u16 * other.0[index] as u16 + quot;
            self.0[index] = (quot & 0x00ffu16) as u8;
            quot = quot >> 8;
        }
    }
}

impl PartialEq for ProofHash {
    fn eq(&self, other: &ProofHash) -> bool {
        for (byte1, byte2) in self.0.iter().zip(other.0.iter()) {
            if byte1 != byte2 {
                return false;
            }
        }
        true
    }
}

impl Eq for ProofHash {}

impl PartialOrd for ProofHash {
    fn partial_cmp(&self, other: &ProofHash) -> Option<Ordering> {
        for (byte1, byte2) in self.0.iter().rev().zip(
            other.0.iter().rev()) {
            if byte1 > byte2 {
                return Some(Ordering::Greater);
            } else if byte2 > byte1 {
                return Some(Ordering::Less);
            }
        }
        return Some(Ordering::Equal);
    }
}

impl Ord for ProofHash {
    fn cmp(&self, other: &ProofHash) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl fmt::Debug for ProofHash {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{:?}", &self.0[])
    }
}

pub struct ThreadedStaker {
    tx_pool: HashSet<String>
}

#[test]
fn test_from_u64() {
    let mut hash1 = ProofHash::from_u64(2100);
    let mut hash2 = ProofHash::from_u64(65535);

    assert!(hash1.0[0] == 52);
    assert!(hash1.0[1] == 8);
    assert!(hash2.0[0] == 255);
    assert!(hash2.0[1] == 255);
    for i in range(3, HASHBYTES) {
        assert!(hash1.0[i] == 0);
        assert!(hash2.0[i] == 0);
    }
}

#[test]
fn test_hash_multiply() {
    let mut hash1 = ProofHash::from_u64(2100);
    let hash2 = ProofHash::from_u64(65535);
    hash1.multiply_in_place(&hash2);
    assert!(hash1.0[0] == 204);
    assert!(hash1.0[1] == 43);
    assert!(hash1.0[2] == 8);
    for i in range(3, HASHBYTES) {
        assert!(hash1.0[i] == 0);
    }

    let mut hash3 = ProofHash::from_u64(65536);
    println!("* hash3: {:?}", hash3);
    println!("* hash3 == hash3: {}", hash3 == hash3);
    println!("* hash3 > hash3: {}", hash3 > hash3);
    println!("* hash3 > hash2: {}", hash3 > hash2);
    println!("* hash3 < hash2: {}", hash3 < hash2);
    // hash3.multiply
}

#[test]
fn test_proof_hash_ord() {
    let hashes = [
        ProofHash::from_u64(0), ProofHash::from_u64(2100),
        ProofHash::from_u64(65535), ProofHash::from_u64(65536),
        ProofHash::from_u64(65536 * 100000)];

    for i in range(0, hashes.len() - 1) {
        for j in range(i + 1, hashes.len()) {
            assert!(hashes[i] < hashes[j]);
            assert!(hashes[j] > hashes[i]);
        }
    }
}

#[test]
fn test_proof_hash() {
    let Digest(target_hash_bytes) = sha512::hash(b"hello world2");
    let target_hash = ProofHash(target_hash_bytes);
    let now_secs = now_utc().to_timespec().sec;
    println!("now_secs = {}", now_secs);
    println!("target_hash = {:?}", target_hash);
    for i in range(0, 100) {
        let Digest(hash_bytes) = sha512::hash(
            format!("{}", now_secs + i).as_bytes());
        let hash = ProofHash(hash_bytes);
        if hash > target_hash {
            println!("hash({}) = {:?}", now_secs + i, hash);
        }
    }
}

// use std::sync::mpsc::{channel, Sender, Receiver};
// struct SimplesService {
//     tx_sender: Sender<simples_pb::Transaction>,
// }

// impl Service for SimplesService {
//     fn pub_transaction(
//         &mut self, request: simples_pb::PublishTransactionRequest) ->
//         SimplesResult<simples_pb::PublishTransactionResponse> {
//             println!("{:?}", request.get_transaction());
//             let response = simples_pb::PublishTransactionResponse::new();
//             Ok(response)
//             // tx_sender.send(msg).unwrap();
//             // let reply = format!("reply");
//         }
// }
<|endoftext|>


<commit_before>use gfx;
use image;
use image::{
    GenericImage,
    ImageBuf,
    Rgba,
};
use texture_lib::ImageSize;

/// Represents a texture.
pub struct Texture {
    /// A handle to the Gfx texture.
    pub handle: gfx::TextureHandle,
}

impl Texture {
    /// Creates a texture from path.
    pub fn from_path<
        C: gfx::CommandBuffer,
        D: gfx::Device<C>
    >(device: &mut D, path: &Path) -> Result<Texture, String> {
        let img = match image::open(path) {
            Ok(img) => img,
            Err(e)  => return Err(format!("Could not load '{}': {}",
                path.filename_str().unwrap(), e)),
        };

        match img.color() {
            image::RGBA(8) => {},
            c => return Err(format!("Unsupported color type {}", c)),
        };

        let (width, height) = img.dimensions();
        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
            img.raw_pixels().as_slice())
        .unwrap();

        Ok(Texture {
            handle: texture
        })
    }

    /// Creates a texture from image.
    pub fn from_image<
        C: gfx::CommandBuffer,
        D: gfx::Device<C>
    >(device: &mut D, image: &ImageBuf<Rgba<u8>>) -> Texture {
        let (width, height) = image.dimensions();
        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
            image.pixelbuf().as_slice())
        .unwrap();

        Texture {
            handle: texture
        }
    }

    /// Creates a texture from RGBA image.
    pub fn from_rgba8<D: gfx::Device<C>, C: gfx::CommandBuffer>(
        img: ImageBuf<Rgba<u8>>,
        d: &mut D
    ) -> Texture {
        let (width, height) = img.dimensions();

        let mut ti = gfx::tex::TextureInfo::new();
        ti.width = width as u16;
        ti.height = height as u16;
        ti.kind = gfx::tex::Texture2D;
        ti.format = gfx::tex::RGBA8;

        let tex = d.create_texture(ti).unwrap();
        d.update_texture(&tex, &ti.to_image_info(),
                         img.into_vec().as_slice()).unwrap();
        d.generate_mipmap(&tex);

        Texture {
            handle: tex,
        }
    }

    /// Updates the texture with an image.
    pub fn update<
        C: gfx::CommandBuffer,
        D: gfx::Device<C>
    >(&mut self, device: &mut D, image: &ImageBuf<Rgba<u8>>) {
        device.update_texture(&self.handle,
            &self.handle.get_info().to_image_info(),
            image.pixelbuf().as_slice()
        ).unwrap();
    }
}

impl ImageSize for Texture {
    fn get_size(&self) -> (u32, u32) {
        let info = self.handle.get_info();
        (info.width as u32, info.height as u32)
    }
}
<commit_msg>Added `get_size`, `get_width` and `get_height` to `Texture`<commit_after>use gfx;
use image;
use image::{
    GenericImage,
    ImageBuf,
    Rgba,
};
use texture_lib::ImageSize;

/// Represents a texture.
pub struct Texture {
    /// A handle to the Gfx texture.
    pub handle: gfx::TextureHandle,
}

impl Texture {
    /// Creates a texture from path.
    pub fn from_path<
        C: gfx::CommandBuffer,
        D: gfx::Device<C>
    >(device: &mut D, path: &Path) -> Result<Texture, String> {
        let img = match image::open(path) {
            Ok(img) => img,
            Err(e)  => return Err(format!("Could not load '{}': {}",
                path.filename_str().unwrap(), e)),
        };

        match img.color() {
            image::RGBA(8) => {},
            c => return Err(format!("Unsupported color type {}", c)),
        };

        let (width, height) = img.dimensions();
        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
            img.raw_pixels().as_slice())
        .unwrap();

        Ok(Texture {
            handle: texture
        })
    }

    /// Creates a texture from image.
    pub fn from_image<
        C: gfx::CommandBuffer,
        D: gfx::Device<C>
    >(device: &mut D, image: &ImageBuf<Rgba<u8>>) -> Texture {
        let (width, height) = image.dimensions();
        let texture_info = gfx::tex::TextureInfo {
            width: width as u16,
            height: height as u16,
            depth: 1,
            levels: 1,
            kind: gfx::tex::Texture2D,
            format: gfx::tex::RGBA8,
        };
        let image_info = texture_info.to_image_info();
        let texture = device.create_texture(texture_info).unwrap();
        device.update_texture(&texture, &image_info,
            image.pixelbuf().as_slice())
        .unwrap();

        Texture {
            handle: texture
        }
    }

    /// Creates a texture from RGBA image.
    pub fn from_rgba8<D: gfx::Device<C>, C: gfx::CommandBuffer>(
        img: ImageBuf<Rgba<u8>>,
        d: &mut D
    ) -> Texture {
        let (width, height) = img.dimensions();

        let mut ti = gfx::tex::TextureInfo::new();
        ti.width = width as u16;
        ti.height = height as u16;
        ti.kind = gfx::tex::Texture2D;
        ti.format = gfx::tex::RGBA8;

        let tex = d.create_texture(ti).unwrap();
        d.update_texture(&tex, &ti.to_image_info(),
                         img.into_vec().as_slice()).unwrap();
        d.generate_mipmap(&tex);

        Texture {
            handle: tex,
        }
    }

    /// Updates the texture with an image.
    pub fn update<
        C: gfx::CommandBuffer,
        D: gfx::Device<C>
    >(&mut self, device: &mut D, image: &ImageBuf<Rgba<u8>>) {
        device.update_texture(&self.handle,
            &self.handle.get_info().to_image_info(),
            image.pixelbuf().as_slice()
        ).unwrap();
    }

    /// Gets the size of the texture.
    #[inline(always)]
    pub fn get_size(&self) -> (u32, u32) {
        let info = self.handle.get_info();
        (info.width as u32, info.height as u32)
    }

    /// Gets the width of the texture.
    #[inline(always)]
    pub fn get_width(&self) -> u32 {
        let (w, _) = self.get_size();
        w
    }

    /// Gets the height of the texture.
    #[inline(always)]
    pub fn get_height(&self) -> u32 {
        let (_, h) = self.get_size();
        h
    }
}

impl ImageSize for Texture {
    #[inline(always)]
    fn get_size(&self) -> (u32, u32) {
        let info = self.handle.get_info();
        (info.width as u32, info.height as u32)
    }
}
<|endoftext|>


<commit_before>//! Parser for the `viewBox` attribute.

use cssparser::Parser;
use std::ops::Deref;

use crate::error::*;
use crate::parsers::{NumberList, Parse};
use crate::rect::Rect;

/// Newtype around a [`Rect`], used to represent the `viewBox` attribute.
///
/// A `ViewBox` is a new user-space coordinate system mapped onto the rectangle defined by
/// the current viewport.  See https://www.w3.org/TR/SVG2/coords.html#ViewBoxAttribute
///
/// `ViewBox` derefs to `Rect`, so you can use `Rect`'s methods and fields directly like
/// `vbox.x0` or `vbox.width()`.
///
/// [`Rect`]: rect/type.Rect.html
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ViewBox(Rect);

impl Deref for ViewBox {
    type Target = Rect;

    fn deref(&self) -> &Rect {
        &self.0
    }
}

impl From<Rect> for ViewBox {
    fn from(r: Rect) -> ViewBox {
        ViewBox(r)
    }
}

impl Parse for ViewBox {
    // Parse a viewBox attribute
    // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
    //
    // viewBox: double [,] double [,] double [,] double [,]
    //
    // x, y, w, h
    //
    // Where w and h must be nonnegative.
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ViewBox, ParseError<'i>> {
        let loc = parser.current_source_location();

        let NumberList::<4, 4>(v) = NumberList::parse(parser)?;
        let (x, y, width, height) = (v[0], v[1], v[2], v[3]);

        if width >= 0.0 && height >= 0.0 {
            Ok(ViewBox(Rect::new(x, y, x + width, y + height)))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error(
                "width and height must not be negative",
            )))
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes() {
        assert_eq!(
            ViewBox::parse_str("  1 2 3 4").unwrap(),
            ViewBox(Rect::new(1.0, 2.0, 4.0, 6.0))
        );

        assert_eq!(
            ViewBox::parse_str(" -1.5 -2.5e1,34,56e2  ").unwrap(),
            ViewBox(Rect::new(-1.5, -25.0, 32.5, 5575.0))
        );
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error() {
        assert!(ViewBox::parse_str("").is_err());
        assert!(ViewBox::parse_str(" 1,2,-3,-4 ").is_err());
        assert!(ViewBox::parse_str("qwerasdfzxcv").is_err());
        assert!(ViewBox::parse_str(" 1 2 3 4   5").is_err());
        assert!(ViewBox::parse_str(" 1 2 foo 3 4").is_err());

        // https://gitlab.gnome.org/GNOME/librsvg/issues/344
        assert!(ViewBox::parse_str("0 0 9E80.7").is_err());
    }
}
<commit_msg>viewbox.rs: links to doc items by name<commit_after>//! Parser for the `viewBox` attribute.

use cssparser::Parser;
use std::ops::Deref;

use crate::error::*;
use crate::parsers::{NumberList, Parse};
use crate::rect::Rect;

/// Newtype around a [`Rect`], used to represent the `viewBox` attribute.
///
/// A `ViewBox` is a new user-space coordinate system mapped onto the rectangle defined by
/// the current viewport.  See https://www.w3.org/TR/SVG2/coords.html#ViewBoxAttribute
///
/// `ViewBox` derefs to [`Rect`], so you can use [`Rect`]'s methods and fields directly like
/// `vbox.x0` or `vbox.width()`.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ViewBox(Rect);

impl Deref for ViewBox {
    type Target = Rect;

    fn deref(&self) -> &Rect {
        &self.0
    }
}

impl From<Rect> for ViewBox {
    fn from(r: Rect) -> ViewBox {
        ViewBox(r)
    }
}

impl Parse for ViewBox {
    // Parse a viewBox attribute
    // https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
    //
    // viewBox: double [,] double [,] double [,] double [,]
    //
    // x, y, w, h
    //
    // Where w and h must be nonnegative.
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<ViewBox, ParseError<'i>> {
        let loc = parser.current_source_location();

        let NumberList::<4, 4>(v) = NumberList::parse(parser)?;
        let (x, y, width, height) = (v[0], v[1], v[2], v[3]);

        if width >= 0.0 && height >= 0.0 {
            Ok(ViewBox(Rect::new(x, y, x + width, y + height)))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error(
                "width and height must not be negative",
            )))
        }
    }
}

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

    #[test]
    fn parses_valid_viewboxes() {
        assert_eq!(
            ViewBox::parse_str("  1 2 3 4").unwrap(),
            ViewBox(Rect::new(1.0, 2.0, 4.0, 6.0))
        );

        assert_eq!(
            ViewBox::parse_str(" -1.5 -2.5e1,34,56e2  ").unwrap(),
            ViewBox(Rect::new(-1.5, -25.0, 32.5, 5575.0))
        );
    }

    #[test]
    fn parsing_invalid_viewboxes_yields_error() {
        assert!(ViewBox::parse_str("").is_err());
        assert!(ViewBox::parse_str(" 1,2,-3,-4 ").is_err());
        assert!(ViewBox::parse_str("qwerasdfzxcv").is_err());
        assert!(ViewBox::parse_str(" 1 2 3 4   5").is_err());
        assert!(ViewBox::parse_str(" 1 2 foo 3 4").is_err());

        // https://gitlab.gnome.org/GNOME/librsvg/issues/344
        assert!(ViewBox::parse_str("0 0 9E80.7").is_err());
    }
}
<|endoftext|>


<commit_before>extern crate kernel32;
extern crate winapi;

use std::fs::File;
use std::io::{Error, Result};
use std::mem;
use std::os::windows::ffi::OsStrExt;
use std::os::windows::io::{AsRawHandle, FromRawHandle};
use std::path::Path;
use std::ptr;

pub fn duplicate(file: &File) -> Result<File> {
    unsafe {
        let mut handle = ptr::null_mut();
        let current_process = kernel32::GetCurrentProcess();
        let ret = kernel32::DuplicateHandle(current_process,
                                            file.as_raw_handle(),
                                            current_process,
                                            &mut handle,
                                            0,
                                            true as winapi::BOOL,
                                            winapi::DUPLICATE_SAME_ACCESS);
        if ret == 0 {
            Err(Error::last_os_error())
        } else {
            Ok(File::from_raw_handle(handle))
        }
    }
}

pub fn allocated_size(file: &File) -> Result<u64> {
    unsafe {
        let mut info: winapi::FILE_STANDARD_INFO = mem::zeroed();

        let ret = kernel32::GetFileInformationByHandleEx(
            file.as_raw_handle(),
            winapi::FileStandardInfo,
            &mut info as *mut _ as *mut _,
            mem::size_of::<winapi::FILE_STANDARD_INFO>() as winapi::DWORD);

        if ret == 0 {
            Err(Error::last_os_error())
        } else {
            Ok(info.AllocationSize as u64)
        }
    }
}

pub fn allocate(file: &File, len: u64) -> Result<()> {
    if try!(allocated_size(file)) < len {
        unsafe {
            let mut info: winapi::FILE_ALLOCATION_INFO = mem::zeroed();
            info.AllocationSize = len as i64;
            let ret = kernel32::SetFileInformationByHandle(
                file.as_raw_handle(),
                winapi::FileAllocationInfo,
                &mut info as *mut _ as *mut _,
                mem::size_of::<winapi::FILE_ALLOCATION_INFO>() as winapi::DWORD);
            if ret == 0 {
                return Err(Error::last_os_error());
            }
        }
    }
    if try!(file.metadata()).len() < len {
        file.set_len(len)
    } else {
        Ok(())
    }
}

pub fn lock_shared(file: &File) -> Result<()> {
    lock_file(file, 0)
}

pub fn lock_exclusive(file: &File) -> Result<()> {
    lock_file(file, winapi::LOCKFILE_EXCLUSIVE_LOCK)
}

pub fn try_lock_shared(file: &File) -> Result<()> {
    lock_file(file, winapi::LOCKFILE_FAIL_IMMEDIATELY)
}

pub fn try_lock_exclusive(file: &File) -> Result<()> {
    lock_file(file, winapi::LOCKFILE_EXCLUSIVE_LOCK | winapi::LOCKFILE_FAIL_IMMEDIATELY)
}

pub fn unlock(file: &File) -> Result<()> {
    unsafe {
        let ret = kernel32::UnlockFile(file.as_raw_handle(), 0, 0, !0, !0);
        if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) }
    }
}

pub fn lock_error() -> Error {
    Error::from_raw_os_error(winapi::ERROR_LOCK_VIOLATION as i32)
}

fn lock_file(file: &File, flags: winapi::DWORD) -> Result<()> {
    unsafe {
        let mut overlapped = mem::zeroed();
        let ret = kernel32::LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped);
        if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) }
    }
}

fn volume_path<P>(path: P, volume_path: &mut [u16]) -> Result<()> where P: AsRef<Path> {
    let path_utf8: Vec<u16> = path.as_ref().as_os_str().encode_wide().chain(Some(0)).collect();
    unsafe {
        let ret = kernel32::GetVolumePathNameW(path_utf8.as_ptr(),
                                               volume_path.as_mut_ptr(),
                                               volume_path.len() as winapi::DWORD);
        if ret == 0 { Err(Error::last_os_error()) } else { Ok(())
        }
    }
}

fn get_disk_free_space<P>(path: P) -> Result<(u64, u64, u64, u64)> where P: AsRef<Path> {
    let root_path: &mut [u16] = &mut [0; 261];
    try!(volume_path(path, root_path));
    unsafe {

        let mut sectors_per_cluster = 0;
        let mut bytes_per_sector = 0;
        let mut number_of_free_clusters = 0;
        let mut total_number_of_clusters = 0;
        let ret = kernel32::GetDiskFreeSpaceW(root_path.as_ptr(),
                                              &mut sectors_per_cluster,
                                              &mut bytes_per_sector,
                                              &mut number_of_free_clusters,
                                              &mut total_number_of_clusters);
        if ret == 0 {
            Err(Error::last_os_error())
        } else {
            Ok((sectors_per_cluster as u64,
                bytes_per_sector as u64,
                number_of_free_clusters as u64,
                total_number_of_clusters as u64))
        }
    }
}

pub fn free_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    available_space(path)
}

pub fn available_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    get_disk_free_space(path).map(|(sectors_per_cluster,
                                    bytes_per_sector,
                                    number_of_free_clusters,
                                    _)| {
        number_of_free_clusters * sectors_per_cluster * bytes_per_sector
    })
}

pub fn total_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    get_disk_free_space(path).map(|(sectors_per_cluster,
                                    bytes_per_sector,
                                    _,
                                    total_number_of_clusters)| {
        total_number_of_clusters * sectors_per_cluster * bytes_per_sector
    })
}

pub fn allocation_granularity<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    get_disk_free_space(path).map(|(sectors_per_cluster, bytes_per_sector, _, _)| {
        sectors_per_cluster * bytes_per_sector
    })
}

#[cfg(test)]
mod test {

    extern crate tempdir;

    use std::fs;
    use std::os::windows::io::AsRawHandle;

    use {FileExt, lock_contended_error};

    /// The duplicate method returns a file with a new file handle.
    #[test]
    fn duplicate_new_handle() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();
        assert!(file1.as_raw_handle() != file2.as_raw_handle());
    }

    /// A duplicated file handle does not have access to the original handle's locks.
    #[test]
    fn lock_duplicate_handle_independence() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();

        // Locking the original file handle will block the duplicate file handle from opening a lock.
        file1.lock_shared().unwrap();
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Once the original file handle is unlocked, the duplicate handle can proceed with a lock.
        file1.unlock().unwrap();
        file2.lock_exclusive().unwrap();
    }

    /// A file handle may not be exclusively locked multiple times, or exclusively locked and then
    /// shared locked.
    #[test]
    fn lock_non_reentrant() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();

        // Multiple exclusive locks fails.
        file.lock_exclusive().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
        file.unlock().unwrap();

        // Shared then Exclusive locks fails.
        file.lock_shared().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
    }

    /// A file handle can hold an exclusive lock and any number of shared locks, all of which must
    /// be unlocked independently.
    #[test]
    fn lock_layering() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();

        // Open two shared locks on the file, and then try and fail to open an exclusive lock.
        file.lock_exclusive().unwrap();
        file.lock_shared().unwrap();
        file.lock_shared().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Pop one of the shared locks and try again.
        file.unlock().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Pop the second shared lock and try again.
        file.unlock().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Pop the exclusive lock and finally succeed.
        file.unlock().unwrap();
        file.lock_exclusive().unwrap();
    }

    /// A file handle with multiple open locks will have all locks closed on drop.
    #[test]
    fn lock_layering_cleanup() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
        let file2 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();

        // Open two shared locks on the file, and then try and fail to open an exclusive lock.
        file1.lock_shared().unwrap();
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        drop(file1);
        file2.lock_exclusive().unwrap();
    }

    /// A file handle's locks will not be released until the original handle and all of its
    /// duplicates have been closed. This on really smells like a bug in Windows.
    #[test]
    fn lock_duplicate_cleanup() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().read(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();

        // Open a lock on the original handle, then close it.
        file1.lock_shared().unwrap();
        drop(file1);

        // Attempting to create a lock on the file with the duplicate handle will fail.
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
    }
}
<commit_msg>Open created files with writable permissions in Windows tests<commit_after>extern crate kernel32;
extern crate winapi;

use std::fs::File;
use std::io::{Error, Result};
use std::mem;
use std::os::windows::ffi::OsStrExt;
use std::os::windows::io::{AsRawHandle, FromRawHandle};
use std::path::Path;
use std::ptr;

pub fn duplicate(file: &File) -> Result<File> {
    unsafe {
        let mut handle = ptr::null_mut();
        let current_process = kernel32::GetCurrentProcess();
        let ret = kernel32::DuplicateHandle(current_process,
                                            file.as_raw_handle(),
                                            current_process,
                                            &mut handle,
                                            0,
                                            true as winapi::BOOL,
                                            winapi::DUPLICATE_SAME_ACCESS);
        if ret == 0 {
            Err(Error::last_os_error())
        } else {
            Ok(File::from_raw_handle(handle))
        }
    }
}

pub fn allocated_size(file: &File) -> Result<u64> {
    unsafe {
        let mut info: winapi::FILE_STANDARD_INFO = mem::zeroed();

        let ret = kernel32::GetFileInformationByHandleEx(
            file.as_raw_handle(),
            winapi::FileStandardInfo,
            &mut info as *mut _ as *mut _,
            mem::size_of::<winapi::FILE_STANDARD_INFO>() as winapi::DWORD);

        if ret == 0 {
            Err(Error::last_os_error())
        } else {
            Ok(info.AllocationSize as u64)
        }
    }
}

pub fn allocate(file: &File, len: u64) -> Result<()> {
    if try!(allocated_size(file)) < len {
        unsafe {
            let mut info: winapi::FILE_ALLOCATION_INFO = mem::zeroed();
            info.AllocationSize = len as i64;
            let ret = kernel32::SetFileInformationByHandle(
                file.as_raw_handle(),
                winapi::FileAllocationInfo,
                &mut info as *mut _ as *mut _,
                mem::size_of::<winapi::FILE_ALLOCATION_INFO>() as winapi::DWORD);
            if ret == 0 {
                return Err(Error::last_os_error());
            }
        }
    }
    if try!(file.metadata()).len() < len {
        file.set_len(len)
    } else {
        Ok(())
    }
}

pub fn lock_shared(file: &File) -> Result<()> {
    lock_file(file, 0)
}

pub fn lock_exclusive(file: &File) -> Result<()> {
    lock_file(file, winapi::LOCKFILE_EXCLUSIVE_LOCK)
}

pub fn try_lock_shared(file: &File) -> Result<()> {
    lock_file(file, winapi::LOCKFILE_FAIL_IMMEDIATELY)
}

pub fn try_lock_exclusive(file: &File) -> Result<()> {
    lock_file(file, winapi::LOCKFILE_EXCLUSIVE_LOCK | winapi::LOCKFILE_FAIL_IMMEDIATELY)
}

pub fn unlock(file: &File) -> Result<()> {
    unsafe {
        let ret = kernel32::UnlockFile(file.as_raw_handle(), 0, 0, !0, !0);
        if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) }
    }
}

pub fn lock_error() -> Error {
    Error::from_raw_os_error(winapi::ERROR_LOCK_VIOLATION as i32)
}

fn lock_file(file: &File, flags: winapi::DWORD) -> Result<()> {
    unsafe {
        let mut overlapped = mem::zeroed();
        let ret = kernel32::LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped);
        if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) }
    }
}

fn volume_path<P>(path: P, volume_path: &mut [u16]) -> Result<()> where P: AsRef<Path> {
    let path_utf8: Vec<u16> = path.as_ref().as_os_str().encode_wide().chain(Some(0)).collect();
    unsafe {
        let ret = kernel32::GetVolumePathNameW(path_utf8.as_ptr(),
                                               volume_path.as_mut_ptr(),
                                               volume_path.len() as winapi::DWORD);
        if ret == 0 { Err(Error::last_os_error()) } else { Ok(())
        }
    }
}

fn get_disk_free_space<P>(path: P) -> Result<(u64, u64, u64, u64)> where P: AsRef<Path> {
    let root_path: &mut [u16] = &mut [0; 261];
    try!(volume_path(path, root_path));
    unsafe {

        let mut sectors_per_cluster = 0;
        let mut bytes_per_sector = 0;
        let mut number_of_free_clusters = 0;
        let mut total_number_of_clusters = 0;
        let ret = kernel32::GetDiskFreeSpaceW(root_path.as_ptr(),
                                              &mut sectors_per_cluster,
                                              &mut bytes_per_sector,
                                              &mut number_of_free_clusters,
                                              &mut total_number_of_clusters);
        if ret == 0 {
            Err(Error::last_os_error())
        } else {
            Ok((sectors_per_cluster as u64,
                bytes_per_sector as u64,
                number_of_free_clusters as u64,
                total_number_of_clusters as u64))
        }
    }
}

pub fn free_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    available_space(path)
}

pub fn available_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    get_disk_free_space(path).map(|(sectors_per_cluster,
                                    bytes_per_sector,
                                    number_of_free_clusters,
                                    _)| {
        number_of_free_clusters * sectors_per_cluster * bytes_per_sector
    })
}

pub fn total_space<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    get_disk_free_space(path).map(|(sectors_per_cluster,
                                    bytes_per_sector,
                                    _,
                                    total_number_of_clusters)| {
        total_number_of_clusters * sectors_per_cluster * bytes_per_sector
    })
}

pub fn allocation_granularity<P>(path: P) -> Result<u64> where P: AsRef<Path> {
    get_disk_free_space(path).map(|(sectors_per_cluster, bytes_per_sector, _, _)| {
        sectors_per_cluster * bytes_per_sector
    })
}

#[cfg(test)]
mod test {

    extern crate tempdir;

    use std::fs;
    use std::os::windows::io::AsRawHandle;

    use {FileExt, lock_contended_error};

    /// The duplicate method returns a file with a new file handle.
    #[test]
    fn duplicate_new_handle() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();
        assert!(file1.as_raw_handle() != file2.as_raw_handle());
    }

    /// A duplicated file handle does not have access to the original handle's locks.
    #[test]
    fn lock_duplicate_handle_independence() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();

        // Locking the original file handle will block the duplicate file handle from opening a lock.
        file1.lock_shared().unwrap();
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Once the original file handle is unlocked, the duplicate handle can proceed with a lock.
        file1.unlock().unwrap();
        file2.lock_exclusive().unwrap();
    }

    /// A file handle may not be exclusively locked multiple times, or exclusively locked and then
    /// shared locked.
    #[test]
    fn lock_non_reentrant() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // Multiple exclusive locks fails.
        file.lock_exclusive().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
        file.unlock().unwrap();

        // Shared then Exclusive locks fails.
        file.lock_shared().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
    }

    /// A file handle can hold an exclusive lock and any number of shared locks, all of which must
    /// be unlocked independently.
    #[test]
    fn lock_layering() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // Open two shared locks on the file, and then try and fail to open an exclusive lock.
        file.lock_exclusive().unwrap();
        file.lock_shared().unwrap();
        file.lock_shared().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Pop one of the shared locks and try again.
        file.unlock().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Pop the second shared lock and try again.
        file.unlock().unwrap();
        assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        // Pop the exclusive lock and finally succeed.
        file.unlock().unwrap();
        file.lock_exclusive().unwrap();
    }

    /// A file handle with multiple open locks will have all locks closed on drop.
    #[test]
    fn lock_layering_cleanup() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
        let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();

        // Open two shared locks on the file, and then try and fail to open an exclusive lock.
        file1.lock_shared().unwrap();
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());

        drop(file1);
        file2.lock_exclusive().unwrap();
    }

    /// A file handle's locks will not be released until the original handle and all of its
    /// duplicates have been closed. This on really smells like a bug in Windows.
    #[test]
    fn lock_duplicate_cleanup() {
        let tempdir = tempdir::TempDir::new("fs2").unwrap();
        let path = tempdir.path().join("fs2");
        let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap();
        let file2 = file1.duplicate().unwrap();

        // Open a lock on the original handle, then close it.
        file1.lock_shared().unwrap();
        drop(file1);

        // Attempting to create a lock on the file with the duplicate handle will fail.
        assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(),
                   lock_contended_error().raw_os_error());
    }
}
<|endoftext|>


<commit_before>use super::{Height, Width};

/// Returns the size of the terminal, if available.
///
/// Note that this returns the size of the actual command window, and
/// not the overall size of the command window buffer
pub fn terminal_size() -> Option<(Width, Height)> {
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::winbase::STD_OUTPUT_HANDLE;
    use winapi::um::wincon::{
        GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT,
    };

    let hand = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };

    if hand == INVALID_HANDLE_VALUE {
        return None;
    }

    let zc = COORD { X: 0, Y: 0 };
    let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
        dwSize: zc,
        dwCursorPosition: zc,
        wAttributes: 0,
        srWindow: SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        },
        dwMaximumWindowSize: zc,
    };
    if unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } != 0 {
        return None;
    }

    let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left + 1) as u16);
    let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) as u16);
    Some((w, h))
}
<commit_msg>Fix terminal_size on Windows<commit_after>use super::{Height, Width};

/// Returns the size of the terminal, if available.
///
/// Note that this returns the size of the actual command window, and
/// not the overall size of the command window buffer
pub fn terminal_size() -> Option<(Width, Height)> {
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::winbase::STD_OUTPUT_HANDLE;
    use winapi::um::wincon::{
        GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT,
    };

    let hand = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };

    if hand == INVALID_HANDLE_VALUE {
        return None;
    }

    let zc = COORD { X: 0, Y: 0 };
    let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
        dwSize: zc,
        dwCursorPosition: zc,
        wAttributes: 0,
        srWindow: SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        },
        dwMaximumWindowSize: zc,
    };
    if unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } == 0 {
        return None;
    }

    let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left + 1) as u16);
    let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) as u16);
    Some((w, h))
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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.

#![allow(missing_debug_implementations)]

//! This module implement all core commands.
use toml::Value;

use std::fs;
use std::path::Path;
use std::net::SocketAddr;
use std::collections::BTreeMap;

use blockchain::GenesisConfig;
use helpers::generate_testnet_config;
use helpers::config::ConfigFile;
use node::{NodeConfig, NodeApiConfig};
use storage::Database;
use crypto;

use blockchain::config::ValidatorKeys;

use super::internal::{Command, Feedback};
use super::{Argument, Context, CommandName};

use super::shared::{AbstractConfig, NodePublicConfig, SharedConfig, NodePrivateConfig,
                    CommonConfigTemplate};
use super::DEFAULT_EXONUM_LISTEN_PORT;

/// Run command.
pub struct Run;

impl Run {
    /// Returns the name of the `Run` command.
    pub fn name() -> CommandName {
        "run"
    }

    /// Returns created database instance.
    pub fn db_helper(ctx: &Context) -> Box<Database> {
        use storage::{RocksDB, RocksDBOptions};

        let path = ctx.arg::<String>("ROCKSDB_PATH").expect(
            "ROCKSDB_PATH not found.",
        );
        let mut options = RocksDBOptions::default();
        options.create_if_missing(true);
        Box::new(RocksDB::open(Path::new(&path), &options).unwrap())
    }

    fn node_config(ctx: &Context) -> NodeConfig {
        let path = ctx.arg::<String>("NODE_CONFIG_PATH").expect(
            "NODE_CONFIG_PATH not found.",
        );
        ConfigFile::load(path).unwrap()
    }

    fn public_api_address(ctx: &Context) -> Option<SocketAddr> {
        ctx.arg("PUBLIC_API_ADDRESS").ok()
    }

    fn private_api_address(ctx: &Context) -> Option<SocketAddr> {
        ctx.arg("PRIVATE_API_ADDRESS").ok()
    }
}

impl Command for Run {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_named(
                "NODE_CONFIG_PATH",
                true,
                "Path to node configuration file.",
                "c",
                "node-config",
                false
            ),
            Argument::new_named(
                "ROCKSDB_PATH",
                true,
                "Use rocksdb database with the given path.",
                "d",
                "rocksdb",
                false
            ),
            Argument::new_named(
                "PUBLIC_API_ADDRESS",
                false,
                "Listen address for public api.",
                None,
                "public-api-address",
                false
            ),
            Argument::new_named(
                "PRIVATE_API_ADDRESS",
                false,
                "Listen address for private api.",
                None,
                "private-api-address",
                false
            ),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Run application"
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let config = Self::node_config(&context);
        let public_addr = Self::public_api_address(&context);
        let private_addr = Self::private_api_address(&context);

        context.set("node_config", config);
        let mut new_context = exts(context);
        let mut config: NodeConfig = new_context.get("node_config").expect(
            "cant load node_config",
        );
        // Override api options

        config.api.public_api_address = public_addr;

        config.api.private_api_address = private_addr;

        new_context.set("node_config", config);

        Feedback::RunNode(new_context)
    }
}

/// Command for the template generation.
pub struct GenerateCommonConfig;

impl GenerateCommonConfig {
    /// Returns the name of the `GenerateCommonConfig` command.
    pub fn name() -> CommandName {
        "generate-template"
    }
}

impl Command for GenerateCommonConfig {
    fn args(&self) -> Vec<Argument> {
        vec![Argument::new_positional("COMMON_CONFIG", true, "Path to common config.")]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Generate basic config template."
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let template_path = context.arg::<String>("COMMON_CONFIG").expect(
            "COMMON_CONFIG not found",
        );

        context.set("services_config", AbstractConfig::default());
        let new_context = exts(context);
        let services_config = new_context.get("services_config").unwrap_or_default();

        let template = CommonConfigTemplate {
            services_config,
            ..CommonConfigTemplate::default()
        };

        ConfigFile::save(&template, template_path).expect("Could not write template file.");
        Feedback::None
    }
}

/// Command for the node configuration generation.
pub struct GenerateNodeConfig;

impl GenerateNodeConfig {
    /// Returns the name of the `GenerateNodeConfig` command.
    pub fn name() -> CommandName {
        "generate-config"
    }

    fn addr(context: &Context) -> (SocketAddr, SocketAddr) {
        let addr = context.arg::<String>("PEER_ADDR").unwrap_or_default();

        let mut addr_parts = addr.split(':');
        let ip = addr_parts.next().expect("Expected ip address");
        if ip.len() < 8 {
            panic!("Expected ip address in PEER_ADDR.")
        }
        let port = addr_parts.next().map_or(DEFAULT_EXONUM_LISTEN_PORT, |s| {
            s.parse().expect("could not parse port")
        });
        let external_addr = format!("{}:{}", ip, port);
        let listen_addr = format!("0.0.0.0:{}", port);
        (external_addr.parse().unwrap(), listen_addr.parse().unwrap())
    }
}

impl Command for GenerateNodeConfig {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_positional("COMMON_CONFIG", true, "Path to common config."),
            Argument::new_positional("PUB_CONFIG", true, "Path where save public config."),
            Argument::new_positional("SEC_CONFIG", true, "Path where save private config."),
            Argument::new_named(
                "PEER_ADDR",
                true,
                "Remote peer address",
                "a",
                "peer-addr",
                false
            ),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Generate node secret and public configs."
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let common_config_path = context.arg::<String>("COMMON_CONFIG").expect(
            "expected common config path",
        );
        let pub_config_path = context.arg::<String>("PUB_CONFIG").expect(
            "expected public config path",
        );
        let priv_config_path = context.arg::<String>("SEC_CONFIG").expect(
            "expected secret config path",
        );

        let addr = Self::addr(&context);
        let common: CommonConfigTemplate =
            ConfigFile::load(&common_config_path).expect("Could not load common config");
        context.set("common_config", common.clone());
        context.set(
            "services_public_configs",
            BTreeMap::<String, Value>::default(),
        );
        context.set(
            "services_secret_configs",
            BTreeMap::<String, Value>::default(),
        );
        let new_context = exts(context);
        let services_public_configs = new_context.get("services_public_configs").unwrap();
        let services_secret_configs = new_context.get("services_secret_configs");

        let (consensus_public_key, consensus_secret_key) = crypto::gen_keypair();
        let (service_public_key, service_secret_key) = crypto::gen_keypair();

        let validator_keys = ValidatorKeys {
            consensus_key: consensus_public_key,
            service_key: service_public_key,
        };
        let node_pub_config = NodePublicConfig {
            addr: addr.0,
            validator_keys,
            services_public_configs,
        };
        let shared_config = SharedConfig {
            node: node_pub_config,
            common: common,
        };
        // Save public config separately.
        ConfigFile::save(&shared_config, &pub_config_path).expect(
            "Could not write public config file.",
        );

        let priv_config = NodePrivateConfig {
            listen_addr: addr.1,
            consensus_public_key,
            consensus_secret_key,
            service_public_key,
            service_secret_key,
            services_secret_configs: services_secret_configs.expect(
                "services_secret_configs not found after exts call",
            ),
        };

        ConfigFile::save(&priv_config, priv_config_path).expect(
            "Could not write secret config file.",
        );
        Feedback::None
    }
}

/// Finalize command.
pub struct Finalize;

impl Finalize {
    /// Returns the name of the `Finalize` command.
    pub fn name() -> CommandName {
        "finalize"
    }

    /// Returns `GenesisConfig` from the template.
    fn genesis_from_template(
        template: CommonConfigTemplate,
        configs: &[NodePublicConfig],
    ) -> GenesisConfig {
        GenesisConfig::new_with_consensus(
            template.consensus_config,
            configs.iter().map(|c| c.validator_keys),
        )
    }

    fn reduce_configs(
        public_configs: Vec<SharedConfig>,
        our_config: &NodePrivateConfig,
    ) -> (CommonConfigTemplate, Vec<NodePublicConfig>, Option<NodePublicConfig>) {
        let mut map = BTreeMap::new();
        let mut config_iter = public_configs.into_iter();
        let first = config_iter.next().expect(
            "Expected at least one config in PUBLIC_CONFIGS",
        );
        let common = first.common;
        map.insert(first.node.validator_keys.consensus_key, first.node);

        for config in config_iter {
            if common != config.common {
                panic!("Found config with different common part.");
            };
            if map.insert(config.node.validator_keys.consensus_key, config.node)
                .is_some()
            {
                panic!("Found duplicate consenus keys in PUBLIC_CONFIGS");
            }

        }
        (
            common,
            map.iter().map(|(_, c)| c.clone()).collect(),
            map.get(&our_config.consensus_public_key).cloned(),
        )
    }
}

impl Command for Finalize {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_named(
                "PUBLIC_CONFIGS",
                true,
                "Path to validators public configs",
                "p",
                "public-configs",
                true
            ),
            Argument::new_named(
                "PUBLIC_API_ADDRESS",
                false,
                "Listen address for public api.",
                None,
                "public-api-address",
                false
            ),
            Argument::new_named(
                "PRIVATE_API_ADDRESS",
                false,
                "Listen address for private api.",
                None,
                "private-api-address",
                false
            ),
            Argument::new_positional("SECRET_CONFIG", true, "Path to our secret config."),
            Argument::new_positional("OUTPUT_CONFIG_PATH", true, "Path to output node config."),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Collect public and secret configs into node config."
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let public_configs_path = context.arg_multiple::<String>("PUBLIC_CONFIGS").expect(
            "keychain path not found",
        );
        let secret_config_path = context.arg::<String>("SECRET_CONFIG").expect(
            "config path not found",
        );
        let output_config_path = context.arg::<String>("OUTPUT_CONFIG_PATH").expect(
            "config path not found",
        );

        let public_addr = Run::public_api_address(&context);
        let private_addr = Run::private_api_address(&context);

        let secret_config: NodePrivateConfig =
            ConfigFile::load(secret_config_path).expect("Failed to load key config.");
        let public_configs: Vec<SharedConfig> = public_configs_path
            .into_iter()
            .map(|path| {
                ConfigFile::load(path).expect("Failed to load validator public config.")
            })
            .collect();
        let (common, list, our) = Self::reduce_configs(public_configs, &secret_config);

        context.set("auditor_mode", our.is_none());

        let peers = list.iter().map(|c| c.addr).collect();

        let genesis = Self::genesis_from_template(common.clone(), &list);

        let config = {
            NodeConfig {
                listen_address: secret_config.listen_addr,
                external_address: our.map(|o| o.addr),
                network: Default::default(),
                whitelist: Default::default(),
                peers: peers,
                consensus_public_key: secret_config.consensus_public_key,
                consensus_secret_key: secret_config.consensus_secret_key,
                service_public_key: secret_config.service_public_key,
                service_secret_key: secret_config.service_secret_key,
                genesis: genesis,
                api: NodeApiConfig {
                    public_api_address: public_addr,
                    private_api_address: private_addr,
                    ..Default::default()
                },
                mempool: Default::default(),
                services_configs: Default::default(),
            }
        };

        context.set("public_config_list", list);
        context.set("node_config", config);
        context.set("common_config", common);
        context.set(
            "services_secret_configs",
            secret_config.services_secret_configs,
        );

        let new_context = exts(context);

        let config: NodeConfig = new_context.get("node_config").expect(
            "Could not create config from template, services return error",
        );
        ConfigFile::save(&config, output_config_path).expect("Could not write config file.");

        Feedback::None
    }
}

/// Command for the testnet generation.
pub struct GenerateTestnet;

impl GenerateTestnet {
    /// Returns the name of the `GenerateTestnet` command.
    pub fn name() -> CommandName {
        "generate-testnet"
    }
}

impl Command for GenerateTestnet {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_named(
                "OUTPUT_DIR",
                true,
                "Path to directory where save configs.",
                "o",
                "output_dir",
                false
            ),
            Argument::new_named(
                "START_PORT",
                false,
                "Port number started from which should validators listen.",
                "p",
                "start",
                false
            ),
            Argument::new_positional("COUNT", true, "Count of validators in testnet."),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Generates genesis configuration for testnet"
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {

        let dir = context.arg::<String>("OUTPUT_DIR").expect("output dir");
        let count: u8 = context.arg("COUNT").expect("count as int");
        let start_port = context.arg::<u16>("START_PORT").unwrap_or(
            DEFAULT_EXONUM_LISTEN_PORT,
        );

        if count == 0 {
            panic!("Can't generate testnet with zero nodes count.");
        }

        let dir = Path::new(&dir);
        let dir = dir.join("validators");
        if !dir.exists() {
            fs::create_dir_all(&dir).unwrap();
        }

        let configs = generate_testnet_config(count, start_port);
        context.set("configs", configs);
        let new_context = exts(context);
        let configs: Vec<NodeConfig> = new_context.get("configs").expect(
            "Couldn't read testnet configs after exts call.",
        );

        for (idx, cfg) in configs.into_iter().enumerate() {
            let file_name = format!("{}.toml", idx);
            ConfigFile::save(&cfg, &dir.join(file_name)).unwrap();
        }

        Feedback::None
    }
}
<commit_msg>Replace 'rocksdb' command line parameter to more generic 'database'<commit_after>// Copyright 2017 The Exonum Team
//
// 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.

#![allow(missing_debug_implementations)]

//! This module implement all core commands.
use toml::Value;

use std::fs;
use std::path::Path;
use std::net::SocketAddr;
use std::collections::BTreeMap;

use blockchain::GenesisConfig;
use helpers::generate_testnet_config;
use helpers::config::ConfigFile;
use node::{NodeConfig, NodeApiConfig};
use storage::Database;
use crypto;

use blockchain::config::ValidatorKeys;

use super::internal::{Command, Feedback};
use super::{Argument, Context, CommandName};

use super::shared::{AbstractConfig, NodePublicConfig, SharedConfig, NodePrivateConfig,
                    CommonConfigTemplate};
use super::DEFAULT_EXONUM_LISTEN_PORT;

const DATABASE_PATH: &str = "DATABASE_PATH";

/// Run command.
pub struct Run;

impl Run {
    /// Returns the name of the `Run` command.
    pub fn name() -> CommandName {
        "run"
    }

    /// Returns created database instance.
    pub fn db_helper(ctx: &Context) -> Box<Database> {
        use storage::{RocksDB, RocksDBOptions};

        let path = ctx.arg::<String>(DATABASE_PATH).expect(
            format!("{} not found.", DATABASE_PATH),
        );
        let mut options = RocksDBOptions::default();
        options.create_if_missing(true);
        Box::new(RocksDB::open(Path::new(&path), &options).unwrap())
    }

    fn node_config(ctx: &Context) -> NodeConfig {
        let path = ctx.arg::<String>("NODE_CONFIG_PATH").expect(
            "NODE_CONFIG_PATH not found.",
        );
        ConfigFile::load(path).unwrap()
    }

    fn public_api_address(ctx: &Context) -> Option<SocketAddr> {
        ctx.arg("PUBLIC_API_ADDRESS").ok()
    }

    fn private_api_address(ctx: &Context) -> Option<SocketAddr> {
        ctx.arg("PRIVATE_API_ADDRESS").ok()
    }
}

impl Command for Run {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_named(
                "NODE_CONFIG_PATH",
                true,
                "Path to node configuration file.",
                "c",
                "node-config",
                false
            ),
            Argument::new_named(
                DATABASE_PATH,
                true,
                "Use database with the given path.",
                "d",
                "database",
                false
            ),
            Argument::new_named(
                "PUBLIC_API_ADDRESS",
                false,
                "Listen address for public api.",
                None,
                "public-api-address",
                false
            ),
            Argument::new_named(
                "PRIVATE_API_ADDRESS",
                false,
                "Listen address for private api.",
                None,
                "private-api-address",
                false
            ),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Run application"
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let config = Self::node_config(&context);
        let public_addr = Self::public_api_address(&context);
        let private_addr = Self::private_api_address(&context);

        context.set("node_config", config);
        let mut new_context = exts(context);
        let mut config: NodeConfig = new_context.get("node_config").expect(
            "cant load node_config",
        );
        // Override api options

        config.api.public_api_address = public_addr;

        config.api.private_api_address = private_addr;

        new_context.set("node_config", config);

        Feedback::RunNode(new_context)
    }
}

/// Command for the template generation.
pub struct GenerateCommonConfig;

impl GenerateCommonConfig {
    /// Returns the name of the `GenerateCommonConfig` command.
    pub fn name() -> CommandName {
        "generate-template"
    }
}

impl Command for GenerateCommonConfig {
    fn args(&self) -> Vec<Argument> {
        vec![Argument::new_positional("COMMON_CONFIG", true, "Path to common config.")]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Generate basic config template."
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let template_path = context.arg::<String>("COMMON_CONFIG").expect(
            "COMMON_CONFIG not found",
        );

        context.set("services_config", AbstractConfig::default());
        let new_context = exts(context);
        let services_config = new_context.get("services_config").unwrap_or_default();

        let template = CommonConfigTemplate {
            services_config,
            ..CommonConfigTemplate::default()
        };

        ConfigFile::save(&template, template_path).expect("Could not write template file.");
        Feedback::None
    }
}

/// Command for the node configuration generation.
pub struct GenerateNodeConfig;

impl GenerateNodeConfig {
    /// Returns the name of the `GenerateNodeConfig` command.
    pub fn name() -> CommandName {
        "generate-config"
    }

    fn addr(context: &Context) -> (SocketAddr, SocketAddr) {
        let addr = context.arg::<String>("PEER_ADDR").unwrap_or_default();

        let mut addr_parts = addr.split(':');
        let ip = addr_parts.next().expect("Expected ip address");
        if ip.len() < 8 {
            panic!("Expected ip address in PEER_ADDR.")
        }
        let port = addr_parts.next().map_or(DEFAULT_EXONUM_LISTEN_PORT, |s| {
            s.parse().expect("could not parse port")
        });
        let external_addr = format!("{}:{}", ip, port);
        let listen_addr = format!("0.0.0.0:{}", port);
        (external_addr.parse().unwrap(), listen_addr.parse().unwrap())
    }
}

impl Command for GenerateNodeConfig {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_positional("COMMON_CONFIG", true, "Path to common config."),
            Argument::new_positional("PUB_CONFIG", true, "Path where save public config."),
            Argument::new_positional("SEC_CONFIG", true, "Path where save private config."),
            Argument::new_named(
                "PEER_ADDR",
                true,
                "Remote peer address",
                "a",
                "peer-addr",
                false
            ),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Generate node secret and public configs."
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let common_config_path = context.arg::<String>("COMMON_CONFIG").expect(
            "expected common config path",
        );
        let pub_config_path = context.arg::<String>("PUB_CONFIG").expect(
            "expected public config path",
        );
        let priv_config_path = context.arg::<String>("SEC_CONFIG").expect(
            "expected secret config path",
        );

        let addr = Self::addr(&context);
        let common: CommonConfigTemplate =
            ConfigFile::load(&common_config_path).expect("Could not load common config");
        context.set("common_config", common.clone());
        context.set(
            "services_public_configs",
            BTreeMap::<String, Value>::default(),
        );
        context.set(
            "services_secret_configs",
            BTreeMap::<String, Value>::default(),
        );
        let new_context = exts(context);
        let services_public_configs = new_context.get("services_public_configs").unwrap();
        let services_secret_configs = new_context.get("services_secret_configs");

        let (consensus_public_key, consensus_secret_key) = crypto::gen_keypair();
        let (service_public_key, service_secret_key) = crypto::gen_keypair();

        let validator_keys = ValidatorKeys {
            consensus_key: consensus_public_key,
            service_key: service_public_key,
        };
        let node_pub_config = NodePublicConfig {
            addr: addr.0,
            validator_keys,
            services_public_configs,
        };
        let shared_config = SharedConfig {
            node: node_pub_config,
            common: common,
        };
        // Save public config separately.
        ConfigFile::save(&shared_config, &pub_config_path).expect(
            "Could not write public config file.",
        );

        let priv_config = NodePrivateConfig {
            listen_addr: addr.1,
            consensus_public_key,
            consensus_secret_key,
            service_public_key,
            service_secret_key,
            services_secret_configs: services_secret_configs.expect(
                "services_secret_configs not found after exts call",
            ),
        };

        ConfigFile::save(&priv_config, priv_config_path).expect(
            "Could not write secret config file.",
        );
        Feedback::None
    }
}

/// Finalize command.
pub struct Finalize;

impl Finalize {
    /// Returns the name of the `Finalize` command.
    pub fn name() -> CommandName {
        "finalize"
    }

    /// Returns `GenesisConfig` from the template.
    fn genesis_from_template(
        template: CommonConfigTemplate,
        configs: &[NodePublicConfig],
    ) -> GenesisConfig {
        GenesisConfig::new_with_consensus(
            template.consensus_config,
            configs.iter().map(|c| c.validator_keys),
        )
    }

    fn reduce_configs(
        public_configs: Vec<SharedConfig>,
        our_config: &NodePrivateConfig,
    ) -> (CommonConfigTemplate, Vec<NodePublicConfig>, Option<NodePublicConfig>) {
        let mut map = BTreeMap::new();
        let mut config_iter = public_configs.into_iter();
        let first = config_iter.next().expect(
            "Expected at least one config in PUBLIC_CONFIGS",
        );
        let common = first.common;
        map.insert(first.node.validator_keys.consensus_key, first.node);

        for config in config_iter {
            if common != config.common {
                panic!("Found config with different common part.");
            };
            if map.insert(config.node.validator_keys.consensus_key, config.node)
                .is_some()
            {
                panic!("Found duplicate consenus keys in PUBLIC_CONFIGS");
            }

        }
        (
            common,
            map.iter().map(|(_, c)| c.clone()).collect(),
            map.get(&our_config.consensus_public_key).cloned(),
        )
    }
}

impl Command for Finalize {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_named(
                "PUBLIC_CONFIGS",
                true,
                "Path to validators public configs",
                "p",
                "public-configs",
                true
            ),
            Argument::new_named(
                "PUBLIC_API_ADDRESS",
                false,
                "Listen address for public api.",
                None,
                "public-api-address",
                false
            ),
            Argument::new_named(
                "PRIVATE_API_ADDRESS",
                false,
                "Listen address for private api.",
                None,
                "private-api-address",
                false
            ),
            Argument::new_positional("SECRET_CONFIG", true, "Path to our secret config."),
            Argument::new_positional("OUTPUT_CONFIG_PATH", true, "Path to output node config."),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Collect public and secret configs into node config."
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {
        let public_configs_path = context.arg_multiple::<String>("PUBLIC_CONFIGS").expect(
            "keychain path not found",
        );
        let secret_config_path = context.arg::<String>("SECRET_CONFIG").expect(
            "config path not found",
        );
        let output_config_path = context.arg::<String>("OUTPUT_CONFIG_PATH").expect(
            "config path not found",
        );

        let public_addr = Run::public_api_address(&context);
        let private_addr = Run::private_api_address(&context);

        let secret_config: NodePrivateConfig =
            ConfigFile::load(secret_config_path).expect("Failed to load key config.");
        let public_configs: Vec<SharedConfig> = public_configs_path
            .into_iter()
            .map(|path| {
                ConfigFile::load(path).expect("Failed to load validator public config.")
            })
            .collect();
        let (common, list, our) = Self::reduce_configs(public_configs, &secret_config);

        context.set("auditor_mode", our.is_none());

        let peers = list.iter().map(|c| c.addr).collect();

        let genesis = Self::genesis_from_template(common.clone(), &list);

        let config = {
            NodeConfig {
                listen_address: secret_config.listen_addr,
                external_address: our.map(|o| o.addr),
                network: Default::default(),
                whitelist: Default::default(),
                peers: peers,
                consensus_public_key: secret_config.consensus_public_key,
                consensus_secret_key: secret_config.consensus_secret_key,
                service_public_key: secret_config.service_public_key,
                service_secret_key: secret_config.service_secret_key,
                genesis: genesis,
                api: NodeApiConfig {
                    public_api_address: public_addr,
                    private_api_address: private_addr,
                    ..Default::default()
                },
                mempool: Default::default(),
                services_configs: Default::default(),
            }
        };

        context.set("public_config_list", list);
        context.set("node_config", config);
        context.set("common_config", common);
        context.set(
            "services_secret_configs",
            secret_config.services_secret_configs,
        );

        let new_context = exts(context);

        let config: NodeConfig = new_context.get("node_config").expect(
            "Could not create config from template, services return error",
        );
        ConfigFile::save(&config, output_config_path).expect("Could not write config file.");

        Feedback::None
    }
}

/// Command for the testnet generation.
pub struct GenerateTestnet;

impl GenerateTestnet {
    /// Returns the name of the `GenerateTestnet` command.
    pub fn name() -> CommandName {
        "generate-testnet"
    }
}

impl Command for GenerateTestnet {
    fn args(&self) -> Vec<Argument> {
        vec![
            Argument::new_named(
                "OUTPUT_DIR",
                true,
                "Path to directory where save configs.",
                "o",
                "output_dir",
                false
            ),
            Argument::new_named(
                "START_PORT",
                false,
                "Port number started from which should validators listen.",
                "p",
                "start",
                false
            ),
            Argument::new_positional("COUNT", true, "Count of validators in testnet."),
        ]
    }

    fn name(&self) -> CommandName {
        Self::name()
    }

    fn about(&self) -> &str {
        "Generates genesis configuration for testnet"
    }

    fn execute(&self, mut context: Context, exts: &Fn(Context) -> Context) -> Feedback {

        let dir = context.arg::<String>("OUTPUT_DIR").expect("output dir");
        let count: u8 = context.arg("COUNT").expect("count as int");
        let start_port = context.arg::<u16>("START_PORT").unwrap_or(
            DEFAULT_EXONUM_LISTEN_PORT,
        );

        if count == 0 {
            panic!("Can't generate testnet with zero nodes count.");
        }

        let dir = Path::new(&dir);
        let dir = dir.join("validators");
        if !dir.exists() {
            fs::create_dir_all(&dir).unwrap();
        }

        let configs = generate_testnet_config(count, start_port);
        context.set("configs", configs);
        let new_context = exts(context);
        let configs: Vec<NodeConfig> = new_context.get("configs").expect(
            "Couldn't read testnet configs after exts call.",
        );

        for (idx, cfg) in configs.into_iter().enumerate() {
            let file_name = format!("{}.toml", idx);
            ConfigFile::save(&cfg, &dir.join(file_name)).unwrap();
        }

        Feedback::None
    }
}
<|endoftext|>


<commit_before>use super::methods::*;
use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use ssz::{ssz_encode, Decodable, Encodable, SszStream};
use std::io;
use std::iter;
use tokio::io::{AsyncRead, AsyncWrite};

/// The maximum bytes that can be sent across the RPC.
const MAX_READ_SIZE: usize = 4_194_304; // 4M

/// Implementation of the `ConnectionUpgrade` for the rpc protocol.

#[derive(Debug, Clone)]
pub struct RPCProtocol;

impl UpgradeInfo for RPCProtocol {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

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

/// The RPC types which are sent/received in this protocol.
#[derive(Debug, Clone)]
pub enum RPCEvent {
    Request {
        id: u64,
        method_id: u16,
        body: RPCRequest,
    },
    Response {
        id: u64,
        method_id: u16, //TODO: Remove and process decoding upstream
        result: RPCResponse,
    },
}

impl UpgradeInfo for RPCEvent {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

impl<TSocket> InboundUpgrade<TSocket> for RPCProtocol
where
    TSocket: AsyncRead + AsyncWrite,
{
    type Output = RPCEvent;
    type Error = DecodeError;
    type Future =
        upgrade::ReadOneThen<TSocket, (), fn(Vec<u8>, ()) -> Result<RPCEvent, DecodeError>>;

    fn upgrade_inbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?))
    }
}

fn decode(packet: Vec<u8>) -> Result<RPCEvent, DecodeError> {
    // decode the header of the rpc
    // request/response
    let (request, index) = bool::ssz_decode(&packet, 0)?;
    let (id, index) = u64::ssz_decode(&packet, index)?;
    let (method_id, index) = u16::ssz_decode(&packet, index)?;

    if request {
        let body = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCRequest::Hello(hello_body)
            }
            RPCMethod::Goodbye => {
                let (goodbye_code, _index) = u64::ssz_decode(&packet, index)?;
                RPCRequest::Goodbye(goodbye_code)
            }
            RPCMethod::BeaconBlockRoots => {
                let (block_roots_request, _index) =
                    BeaconBlockRootsRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockRoots(block_roots_request)
            }
            RPCMethod::BeaconBlockHeaders => {
                let (block_headers_request, _index) =
                    BeaconBlockHeadersRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockHeaders(block_headers_request)
            }
            RPCMethod::BeaconBlockBodies => {
                let (block_bodies_request, _index) =
                    BeaconBlockBodiesRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockBodies(block_bodies_request)
            }
            RPCMethod::BeaconChainState => {
                let (chain_state_request, _index) =
                    BeaconChainStateRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconChainState(chain_state_request)
            }
            RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod),
        };

        Ok(RPCEvent::Request {
            id,
            method_id,
            body,
        })
    }
    // we have received a response
    else {
        let result = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCResponse::Hello(body)
            }
            RPCMethod::Goodbye => unreachable!("Should never receive a goodbye response"),
            RPCMethod::BeaconBlockRoots => {
                let (body, _index) = BeaconBlockRootsResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockRoots(body)
            }
            RPCMethod::BeaconBlockHeaders => {
                let (body, _index) = BeaconBlockHeadersResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockHeaders(body)
            }
            RPCMethod::BeaconBlockBodies => {
                let (body, _index) = BeaconBlockBodiesResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockBodies(body)
            }
            RPCMethod::BeaconChainState => {
                let (body, _index) = BeaconChainStateResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconChainState(body)
            }
            RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod),
        };
        Ok(RPCEvent::Response {
            id,
            method_id,
            result,
        })
    }
}

impl<TSocket> OutboundUpgrade<TSocket> for RPCEvent
where
    TSocket: AsyncWrite,
{
    type Output = ();
    type Error = io::Error;
    type Future = upgrade::WriteOne<TSocket>;

    #[inline]
    fn upgrade_outbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        let bytes = ssz_encode(&self);
        upgrade::write_one(socket, bytes)
    }
}

impl Encodable for RPCEvent {
    fn ssz_append(&self, s: &mut SszStream) {
        match self {
            RPCEvent::Request {
                id,
                method_id,
                body,
            } => {
                s.append(&true);
                s.append(id);
                s.append(method_id);
                match body {
                    RPCRequest::Hello(body) => {
                        s.append(body);
                    }
                    _ => {}
                }
            }
            RPCEvent::Response {
                id,
                method_id,
                result,
            } => {
                s.append(&false);
                s.append(id);
                s.append(method_id);
                match result {
                    RPCResponse::Hello(response) => {
                        s.append(response);
                    }
                    _ => {}
                }
            }
        }
    }
}

#[derive(Debug)]
pub enum DecodeError {
    ReadError(upgrade::ReadOneError),
    SSZDecodeError(ssz::DecodeError),
    UnknownRPCMethod,
}

impl From<upgrade::ReadOneError> for DecodeError {
    #[inline]
    fn from(err: upgrade::ReadOneError) -> Self {
        DecodeError::ReadError(err)
    }
}

impl From<ssz::DecodeError> for DecodeError {
    #[inline]
    fn from(err: ssz::DecodeError) -> Self {
        DecodeError::SSZDecodeError(err)
    }
}
<commit_msg>Implement encodeable on all RPC methods<commit_after>use super::methods::*;
use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo};
use ssz::{ssz_encode, Decodable, Encodable, SszStream};
use std::io;
use std::iter;
use tokio::io::{AsyncRead, AsyncWrite};

/// The maximum bytes that can be sent across the RPC.
const MAX_READ_SIZE: usize = 4_194_304; // 4M

/// Implementation of the `ConnectionUpgrade` for the rpc protocol.

#[derive(Debug, Clone)]
pub struct RPCProtocol;

impl UpgradeInfo for RPCProtocol {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

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

/// The RPC types which are sent/received in this protocol.
#[derive(Debug, Clone)]
pub enum RPCEvent {
    Request {
        id: u64,
        method_id: u16,
        body: RPCRequest,
    },
    Response {
        id: u64,
        method_id: u16, //TODO: Remove and process decoding upstream
        result: RPCResponse,
    },
}

impl UpgradeInfo for RPCEvent {
    type Info = &'static [u8];
    type InfoIter = iter::Once<Self::Info>;

    #[inline]
    fn protocol_info(&self) -> Self::InfoIter {
        iter::once(b"/eth/serenity/rpc/1.0.0")
    }
}

impl<TSocket> InboundUpgrade<TSocket> for RPCProtocol
where
    TSocket: AsyncRead + AsyncWrite,
{
    type Output = RPCEvent;
    type Error = DecodeError;
    type Future =
        upgrade::ReadOneThen<TSocket, (), fn(Vec<u8>, ()) -> Result<RPCEvent, DecodeError>>;

    fn upgrade_inbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        upgrade::read_one_then(socket, MAX_READ_SIZE, (), |packet, ()| Ok(decode(packet)?))
    }
}

fn decode(packet: Vec<u8>) -> Result<RPCEvent, DecodeError> {
    // decode the header of the rpc
    // request/response
    let (request, index) = bool::ssz_decode(&packet, 0)?;
    let (id, index) = u64::ssz_decode(&packet, index)?;
    let (method_id, index) = u16::ssz_decode(&packet, index)?;

    if request {
        let body = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (hello_body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCRequest::Hello(hello_body)
            }
            RPCMethod::Goodbye => {
                let (goodbye_code, _index) = u64::ssz_decode(&packet, index)?;
                RPCRequest::Goodbye(goodbye_code)
            }
            RPCMethod::BeaconBlockRoots => {
                let (block_roots_request, _index) =
                    BeaconBlockRootsRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockRoots(block_roots_request)
            }
            RPCMethod::BeaconBlockHeaders => {
                let (block_headers_request, _index) =
                    BeaconBlockHeadersRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockHeaders(block_headers_request)
            }
            RPCMethod::BeaconBlockBodies => {
                let (block_bodies_request, _index) =
                    BeaconBlockBodiesRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconBlockBodies(block_bodies_request)
            }
            RPCMethod::BeaconChainState => {
                let (chain_state_request, _index) =
                    BeaconChainStateRequest::ssz_decode(&packet, index)?;
                RPCRequest::BeaconChainState(chain_state_request)
            }
            RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod),
        };

        Ok(RPCEvent::Request {
            id,
            method_id,
            body,
        })
    }
    // we have received a response
    else {
        let result = match RPCMethod::from(method_id) {
            RPCMethod::Hello => {
                let (body, _index) = HelloMessage::ssz_decode(&packet, index)?;
                RPCResponse::Hello(body)
            }
            RPCMethod::Goodbye => unreachable!("Should never receive a goodbye response"),
            RPCMethod::BeaconBlockRoots => {
                let (body, _index) = BeaconBlockRootsResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockRoots(body)
            }
            RPCMethod::BeaconBlockHeaders => {
                let (body, _index) = BeaconBlockHeadersResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockHeaders(body)
            }
            RPCMethod::BeaconBlockBodies => {
                let (body, _index) = BeaconBlockBodiesResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconBlockBodies(body)
            }
            RPCMethod::BeaconChainState => {
                let (body, _index) = BeaconChainStateResponse::ssz_decode(&packet, index)?;
                RPCResponse::BeaconChainState(body)
            }
            RPCMethod::Unknown => return Err(DecodeError::UnknownRPCMethod),
        };
        Ok(RPCEvent::Response {
            id,
            method_id,
            result,
        })
    }
}

impl<TSocket> OutboundUpgrade<TSocket> for RPCEvent
where
    TSocket: AsyncWrite,
{
    type Output = ();
    type Error = io::Error;
    type Future = upgrade::WriteOne<TSocket>;

    #[inline]
    fn upgrade_outbound(self, socket: TSocket, _: Self::Info) -> Self::Future {
        let bytes = ssz_encode(&self);
        upgrade::write_one(socket, bytes)
    }
}

impl Encodable for RPCEvent {
    fn ssz_append(&self, s: &mut SszStream) {
        match self {
            RPCEvent::Request {
                id,
                method_id,
                body,
            } => {
                s.append(&true);
                s.append(id);
                s.append(method_id);
                match body {
                    RPCRequest::Hello(body) => {
                        s.append(body);
                    }
                    RPCRequest::Goodbye(body) => {
                        s.append(body);
                    }
                    RPCRequest::BeaconBlockRoots(body) => {
                        s.append(body);
                    }
                    RPCRequest::BeaconBlockHeaders(body) => {
                        s.append(body);
                    }
                    RPCRequest::BeaconBlockBodies(body) => {
                        s.append(body);
                    }
                    RPCRequest::BeaconChainState(body) => {
                        s.append(body);
                    }
                }
            }
            RPCEvent::Response {
                id,
                method_id,
                result,
            } => {
                s.append(&false);
                s.append(id);
                s.append(method_id);
                match result {
                    RPCResponse::Hello(response) => {
                        s.append(response);
                    }
                    RPCResponse::BeaconBlockRoots(response) => {
                        s.append(response);
                    }
                    RPCResponse::BeaconBlockHeaders(response) => {
                        s.append(response);
                    }
                    RPCResponse::BeaconBlockBodies(response) => {
                        s.append(response);
                    }
                    RPCResponse::BeaconChainState(response) => {
                        s.append(response);
                    }
                }
            }
        }
    }
}

#[derive(Debug)]
pub enum DecodeError {
    ReadError(upgrade::ReadOneError),
    SSZDecodeError(ssz::DecodeError),
    UnknownRPCMethod,
}

impl From<upgrade::ReadOneError> for DecodeError {
    #[inline]
    fn from(err: upgrade::ReadOneError) -> Self {
        DecodeError::ReadError(err)
    }
}

impl From<ssz::DecodeError> for DecodeError {
    #[inline]
    fn from(err: ssz::DecodeError) -> Self {
        DecodeError::SSZDecodeError(err)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate slog;

extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_uds;

extern crate rdmcommon;

use slog::Logger;

use futures::{Future, Stream, Sink};

use tokio_core::reactor::{Core, Handle};
use tokio_io::AsyncRead;
use tokio_uds::UnixStream;

use std::io;

use rdmcommon::ipc;
use rdmcommon::util;

pub struct RdmGreeter {
    core: Core,
    receiver: Box<Stream<Item = ipc::IpcMessage, Error = ipc::IpcError>>,
    sender: Box<Sink<SinkItem = ipc::IpcMessage, SinkError = ipc::IpcError>>,
    log: Logger
}

pub enum RdmGreeterError {
    Ipc(ipc::IpcError),
    Io(io::Error),
    FailedHandshake
}

impl From<io::Error> for RdmGreeterError {
    fn from(err: io::Error) -> RdmGreeterError {
        RdmGreeterError::Io(err)
    }
}

impl From<ipc::IpcError> for RdmGreeterError {
    fn from(err: ipc::IpcError) -> RdmGreeterError {
        RdmGreeterError::Ipc(err)
    }
}

impl RdmGreeter {
    pub fn new<L : Into<Option<Logger>>>(logger: L) -> Result<RdmGreeter, RdmGreeterError> {
        let log = logger.into().unwrap_or(util::plain_logger());
        let mut core = Core::new()?;
        let handle = core.handle();
        // TODO: move this into private fn
        debug!(log, "[RdmGreeter::new] Connecting server socket");
        let sock = UnixStream::connect("/home/florian/tmp/sock", &handle)?;
        let (tx, rx) = sock.framed(ipc::IpcMessageCodec).split();
        debug!(log, "[RdmGreeter::new] Sending ClientHello");
        let tx = core.run(tx.send(ipc::IpcMessage::ClientHello))?;
        debug!(log, "[RdmGreeter::new] Reading server response");
        let (resp, rx) = core.run(rx.take(1).into_future().map_err(|(err, _)| err))?;

        debug!(log, "[RdmGreeter::new] Got server response"; "response" => ?resp);
        match resp {
            Some(ipc::IpcMessage::ServerHello) => Ok(RdmGreeter {
                                                        core: core,
                                                        receiver: Box::new(rx),
                                                        sender: Box::new(tx),
                                                        log: log,
                                                  }),
            _ => Err(RdmGreeterError::FailedHandshake)
        }
    }
}

impl Drop for RdmGreeter {
    fn drop(&mut self) {
        debug!(self.log, "[RdmGreeter::drop] Dropping RdmGreeter..");
    }
}<commit_msg>[libgreeter] Derive Debug for RdmGreeterError<commit_after>#[macro_use]
extern crate slog;

extern crate futures;
extern crate tokio_core;
extern crate tokio_io;
extern crate tokio_uds;

extern crate rdmcommon;

use std::io;

use rdmcommon::ipc;
use rdmcommon::util;

use futures::{Future, Stream, Sink};
use slog::Logger;
use tokio_core::reactor::{Core, Handle};
use tokio_io::AsyncRead;
use tokio_uds::UnixStream;

pub struct RdmGreeter {
    log: Logger,
    core: Core,
    receiver: Box<Stream<Item = ipc::IpcMessage, Error = ipc::IpcError>>,
    sender: Box<Sink<SinkItem = ipc::IpcMessage, SinkError = ipc::IpcError>>,
}

#[derive(Debug)]
pub enum RdmGreeterError {
    Ipc(ipc::IpcError),
    Io(io::Error),
    FailedHandshake
}

impl From<io::Error> for RdmGreeterError {
    fn from(err: io::Error) -> RdmGreeterError {
        RdmGreeterError::Io(err)
    }
}

impl From<ipc::IpcError> for RdmGreeterError {
    fn from(err: ipc::IpcError) -> RdmGreeterError {
        RdmGreeterError::Ipc(err)
    }
}

impl RdmGreeter {
    pub fn new<L : Into<Option<Logger>>>(logger: L) -> Result<RdmGreeter, RdmGreeterError> {
        let log = logger.into().unwrap_or(util::plain_logger());
        let mut core = Core::new()?;
        let handle = core.handle();
        // TODO: move this into private fn
        debug!(log, "[RdmGreeter::new] Connecting server socket");
        let sock = UnixStream::connect("/home/florian/tmp/sock", &handle)?;
        let (tx, rx) = sock.framed(ipc::IpcMessageCodec).split();

        debug!(log, "[RdmGreeter::new] Sending ClientHello");
        let tx = core.run(tx.send(ipc::IpcMessage::ClientHello))?;

        debug!(log, "[RdmGreeter::new] Reading server response");
        let (resp, rx) = core.run(rx.take(1).into_future().map_err(|(err, _)| err))?;
        debug!(log, "[RdmGreeter::new] Got server response"; "response" => ?resp);

        match resp {
            Some(ipc::IpcMessage::ServerHello) => Ok(RdmGreeter {
                                                        core: core,
                                                        receiver: Box::new(rx),
                                                        sender: Box::new(tx),
                                                        log: log,
                                                  }),
            _ => Err(RdmGreeterError::FailedHandshake)
        }
    }
}

impl Drop for RdmGreeter {
    fn drop(&mut self) {
        debug!(self.log, "[RdmGreeter::drop] Dropping RdmGreeter..");
    }
}<|endoftext|>