<commit_before>extern crate libc;
use std::ptr;
use std::str;
use std::ffi::CStr;
use std::fmt::{self, Display, Debug, Formatter, Error};
use capstone_sys::{cs_free, cs_insn, cs_detail};

/// Representation of the array of instructions returned by disasm
#[derive(Debug)]
pub struct Instructions {
    ptr: *mut cs_insn,
    len: isize,
}

impl Instructions {
    pub unsafe fn from_raw_parts(ptr: *mut cs_insn, len: isize) -> Instructions {
        Instructions {
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

     pub fn iter(&self) -> InstructionIterator {
         InstructionIterator {
             insns: &self,
             cur: 0,
         }
     }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }
}

impl Drop for Instructions {
     fn drop(&mut self) {
         unsafe {
             cs_free(self.ptr, self.len as libc::size_t);
         }
     }
}

/// An iterator over the instructions returned by disasm
///
/// This is currently the only supported interface for reading them.
pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { Insn::from(ptr::read(obj)) })
        }
    }
}

/// A wrapper for the raw capstone-sys instruction
pub struct Insn(cs_insn);

/// A wrapper for the raw capstone-sys detail struct, which contains register information in addition
/// to architecture specific information (not implemented in capstone-sys yet)
pub struct Detail(cs_detail);

use std::convert::From;

impl From<cs_insn> for Insn {
    fn from(insn: cs_insn) -> Self {
        Insn (insn)
    }
}

impl From<cs_detail> for Detail{
    fn from(detail: cs_detail) -> Self {
        Detail (detail)
    }
}

impl Insn {
    /// The mnemonic for the instruction
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.0.mnemonic.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// The operand string associated with the instruction
    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.0.op_str.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// Size of instruction (in bytes)
    pub fn len (&self) -> usize {
        self.0.size as usize
    }

    pub fn address (&self) -> u64 {
        self.0.address as u64
    }

    /// Byte-level representation of the instruction
    pub fn bytes (&self) -> &[u8] {
        &self.0.bytes[..self.len()]
    }

    /// Returns the detail object, if there is one.
    ///
    /// Be careful this is still in early stages and largely untested with various `cs_option` and
    /// architecture matrices
    pub fn detail (&self) -> Option<Detail> {
        if self.0.detail.is_null() {
            None
        } else {
            Some(Detail::from(unsafe { ptr::read(self.0.detail) }))
        }
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address())
            .field("len", &self.len())
            .field("bytes", &self.bytes())
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}

impl Display for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{:#x}: ", self.address())?;
        if let Some(mnemonic) = self.mnemonic() {
            write!(fmt, "{} ", mnemonic)?;
            if let Some(op_str) = self.op_str() {
                write!(fmt, "{}", op_str)?;
            }
        }
        Ok(())
    }
}

impl Detail {
    /// list of implicit registers read by this insn
    pub fn regs_read(&self) -> &[libc::uint8_t; 12] {
        &self.0.regs_read
    }
    /// number of implicit registers read by this insn
    pub fn regs_read_count(&self) -> libc::uint8_t {
        self.0.regs_read_count
    }
    /// list of implicit registers modified by this insn
    pub fn regs_write(&self) -> &[libc::uint8_t; 20] {
        &self.0.regs_write
    }
    /// number of implicit registers modified by this insn
    pub fn regs_write_count(&self) -> libc::uint8_t {
        self.0.regs_write_count
    }
    /// list of group this instruction belong to
    pub fn groups(&self) -> &[libc::uint8_t; 8] {
        &self.0.groups
    }
    /// number of groups this insn belongs to
    pub fn groups_count(&self) -> libc::uint8_t {
        self.0.groups_count
    }

}

impl Debug for Detail {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Detail")
            .field("regs_read", &self.regs_read())
            .field("regs_read_count", &self.regs_read_count())
            .field("regs_write", &self.regs_write())
            .field("regs_write_count", &self.regs_write_count())
            .field("groups", &self.groups())
            .field("groups_count", &self.groups_count())
            .finish()
    }
}

impl Display for Instructions {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        for sym in self.iter() {
            write!(fmt, "{:x}:\t", sym.address())?;
            for byte in sym.bytes() {
                write!(fmt, " {:02x}", byte)?;
            }
            let remainder = 16*3 - (sym.bytes().len())*3;
            for _ in 0..remainder {
                write!(fmt, " ")?;
            }
            if let Some(mnemonic) = sym.mnemonic() {
                write!(fmt, " {}", mnemonic)?;
                if let Some(op_str) = sym.op_str() {
                    write!(fmt, " {}", op_str)?;
                }
            }
            write!(fmt, "\n")?;
        }
        Ok(())
    }
}
<commit_msg>instruction: replace sym with instruction<commit_after>extern crate libc;
use std::ptr;
use std::str;
use std::ffi::CStr;
use std::fmt::{self, Display, Debug, Formatter, Error};
use capstone_sys::{cs_free, cs_insn, cs_detail};

/// Representation of the array of instructions returned by disasm
#[derive(Debug)]
pub struct Instructions {
    ptr: *mut cs_insn,
    len: isize,
}

impl Instructions {
    pub unsafe fn from_raw_parts(ptr: *mut cs_insn, len: isize) -> Instructions {
        Instructions {
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

     pub fn iter(&self) -> InstructionIterator {
         InstructionIterator {
             insns: &self,
             cur: 0,
         }
     }

    pub fn is_empty(&self) -> bool {
        self.len == 0
    }
}

impl Drop for Instructions {
     fn drop(&mut self) {
         unsafe {
             cs_free(self.ptr, self.len as libc::size_t);
         }
     }
}

/// An iterator over the instructions returned by disasm
///
/// This is currently the only supported interface for reading them.
pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { Insn::from(ptr::read(obj)) })
        }
    }
}

/// A wrapper for the raw capstone-sys instruction
pub struct Insn(cs_insn);

/// A wrapper for the raw capstone-sys detail struct, which contains register information in addition
/// to architecture specific information (not implemented in capstone-sys yet)
pub struct Detail(cs_detail);

use std::convert::From;

impl From<cs_insn> for Insn {
    fn from(insn: cs_insn) -> Self {
        Insn (insn)
    }
}

impl From<cs_detail> for Detail{
    fn from(detail: cs_detail) -> Self {
        Detail (detail)
    }
}

impl Insn {
    /// The mnemonic for the instruction
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.0.mnemonic.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// The operand string associated with the instruction
    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.0.op_str.as_ptr()) };
        str::from_utf8(cstr.to_bytes()).ok()
    }

    /// Size of instruction (in bytes)
    pub fn len (&self) -> usize {
        self.0.size as usize
    }

    pub fn address (&self) -> u64 {
        self.0.address as u64
    }

    /// Byte-level representation of the instruction
    pub fn bytes (&self) -> &[u8] {
        &self.0.bytes[..self.len()]
    }

    /// Returns the detail object, if there is one.
    ///
    /// Be careful this is still in early stages and largely untested with various `cs_option` and
    /// architecture matrices
    pub fn detail (&self) -> Option<Detail> {
        if self.0.detail.is_null() {
            None
        } else {
            Some(Detail::from(unsafe { ptr::read(self.0.detail) }))
        }
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Insn")
            .field("address", &self.address())
            .field("len", &self.len())
            .field("bytes", &self.bytes())
            .field("mnemonic", &self.mnemonic())
            .field("op_str", &self.op_str())
            .finish()
    }
}

impl Display for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "{:#x}: ", self.address())?;
        if let Some(mnemonic) = self.mnemonic() {
            write!(fmt, "{} ", mnemonic)?;
            if let Some(op_str) = self.op_str() {
                write!(fmt, "{}", op_str)?;
            }
        }
        Ok(())
    }
}

impl Detail {
    /// list of implicit registers read by this insn
    pub fn regs_read(&self) -> &[libc::uint8_t; 12] {
        &self.0.regs_read
    }
    /// number of implicit registers read by this insn
    pub fn regs_read_count(&self) -> libc::uint8_t {
        self.0.regs_read_count
    }
    /// list of implicit registers modified by this insn
    pub fn regs_write(&self) -> &[libc::uint8_t; 20] {
        &self.0.regs_write
    }
    /// number of implicit registers modified by this insn
    pub fn regs_write_count(&self) -> libc::uint8_t {
        self.0.regs_write_count
    }
    /// list of group this instruction belong to
    pub fn groups(&self) -> &[libc::uint8_t; 8] {
        &self.0.groups
    }
    /// number of groups this insn belongs to
    pub fn groups_count(&self) -> libc::uint8_t {
        self.0.groups_count
    }

}

impl Debug for Detail {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        fmt.debug_struct("Detail")
            .field("regs_read", &self.regs_read())
            .field("regs_read_count", &self.regs_read_count())
            .field("regs_write", &self.regs_write())
            .field("regs_write_count", &self.regs_write_count())
            .field("groups", &self.groups())
            .field("groups_count", &self.groups_count())
            .finish()
    }
}

impl Display for Instructions {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        for instruction in self.iter() {
            write!(fmt, "{:x}:\t", instruction.address())?;
            for byte in instruction.bytes() {
                write!(fmt, " {:02x}", byte)?;
            }
            let remainder = 16*3 - (instruction.bytes().len())*3;
            for _ in 0..remainder {
                write!(fmt, " ")?;
            }
            if let Some(mnemonic) = instruction.mnemonic() {
                write!(fmt, " {}", mnemonic)?;
                if let Some(op_str) = instruction.op_str() {
                    write!(fmt, " {}", op_str)?;
                }
            }
            write!(fmt, "\n")?;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Walter Kuppens.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fs::File;
use std::io::Error;
use std::io::Read;
use std::path::Path;
use std::result::Result;

// Used to identify a rom as being in the iNES format. This byte sequence should
// be at the start of every rom.
const INES_IDENTIFIER: [u8; 4] = [0x4E, 0x45, 0x53, 0x1A];

/// Structure that represents the 16 byte header of an iNES rom. Only missing
/// the zero fill as it's unused space.
#[derive(Debug)]
pub struct INESHeader {
    identifier: [u8; 4], // File format identifier.
    prg_rom_size: u8,    // Size of PRG ROM in 16 KB units.
    chr_rom_size: u8,    // Size of CHR ROM in 8 KB units.
    flags_6: u8,
    flags_7: u8,
    prg_ram_size: u8,    // Size of PRG RAM in 8 KB units (0 infers 8 KB for compatibility).
    flags_9: u8,
    flags_10: u8         // Unofficial, unused by most emulators.
}

/// Reads a binary file at a given path and stores it in a vector of bytes.
pub fn read_bin<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
    let mut buffer: Vec<u8> = Vec::new();
    match File::open(path) {
        Ok(mut file) => {
            file.read_to_end(&mut buffer).unwrap();
        },
        Err(e) => return Err(e)
    }
    Ok(buffer)
}

/// Parses the header of a rom (assumed to be in the iNES format).
///
/// The first 16 bytes of the rom contain the header. The iNES format is
/// identified by the literal byte string "NES<0x1A>". If the rom is not in the
/// iNES format, then it cannot be executed by the emulator.
pub fn parse_rom_header(rom: &[u8]) -> Result<INESHeader, &str> {
    // The header takes at least 0x10 bytes of space at the start of the rom.
    let invalid_header = "rom does not contain iNES identifier and is invalid";
    if rom.len() < 0x10 {
        return Err(invalid_header)
    }

    // Validate that the rom is formatted in the iNES format.
    let identifier = &rom[0x0..0x4];
    if identifier != INES_IDENTIFIER {
        return Err(invalid_header)
    }

    // Copy the identifier from the rom for placement in the header.
    let mut new_identifier: [u8; 4] = [0; 4];
    new_identifier.copy_from_slice(identifier);

    // Return an iNES header containing fields filled in from the rom.
    Ok(INESHeader {
        identifier: new_identifier,
        prg_rom_size: rom[0x4],
        chr_rom_size: rom[0x5],
        flags_6: rom[0x6],
        flags_7: rom[0x7],
        prg_ram_size: rom[0x8],
        flags_9: rom[0x9],
        flags_10: rom[0xA]
    })
}
<commit_msg>Replaced some error handling with try!<commit_after>// Copyright 2016 Walter Kuppens.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fs::File;
use std::io::Error;
use std::io::Read;
use std::path::Path;
use std::result::Result;

// Used to identify a rom as being in the iNES format. This byte sequence should
// be at the start of every rom.
const INES_IDENTIFIER: [u8; 4] = [0x4E, 0x45, 0x53, 0x1A];

/// Structure that represents the 16 byte header of an iNES rom. Only missing
/// the zero fill as it's unused space.
#[derive(Debug)]
pub struct INESHeader {
    identifier: [u8; 4], // File format identifier.
    prg_rom_size: u8,    // Size of PRG ROM in 16 KB units.
    chr_rom_size: u8,    // Size of CHR ROM in 8 KB units.
    flags_6: u8,
    flags_7: u8,
    prg_ram_size: u8,    // Size of PRG RAM in 8 KB units (0 infers 8 KB for compatibility).
    flags_9: u8,
    flags_10: u8         // Unofficial, unused by most emulators.
}

/// Reads a binary file at a given path and stores it in a vector of bytes.
pub fn read_bin<P: AsRef<Path>>(path: P) -> Result<Vec<u8>, Error> {
    let mut buffer: Vec<u8> = Vec::new();
    let mut file = try!(File::open(path));
    try!(file.read_to_end(&mut buffer));
    Ok(buffer)
}

/// Parses the header of a rom (assumed to be in the iNES format).
///
/// The first 16 bytes of the rom contain the header. The iNES format is
/// identified by the literal byte string "NES<0x1A>". If the rom is not in the
/// iNES format, then it cannot be executed by the emulator.
pub fn parse_rom_header(rom: &[u8]) -> Result<INESHeader, &str> {
    // The header takes at least 0x10 bytes of space at the start of the rom.
    let invalid_header = "rom does not contain iNES identifier and is invalid";
    if rom.len() < 0x10 {
        return Err(invalid_header)
    }

    // Validate that the rom is formatted in the iNES format.
    let identifier = &rom[0x0..0x4];
    if identifier != INES_IDENTIFIER {
        return Err(invalid_header)
    }

    // Copy the identifier from the rom for placement in the header.
    let mut new_identifier: [u8; 4] = [0; 4];
    new_identifier.copy_from_slice(identifier);

    // Return an iNES header containing fields filled in from the rom.
    Ok(INESHeader {
        identifier: new_identifier,
        prg_rom_size: rom[0x4],
        chr_rom_size: rom[0x5],
        flags_6: rom[0x6],
        flags_7: rom[0x7],
        prg_ram_size: rom[0x8],
        flags_9: rom[0x9],
        flags_10: rom[0xA]
    })
}
<|endoftext|>


<commit_before>///! All actors from webui are represented here
use super::{
    super::super::ctrl::InternalUiMsg,
    json::{self, WSJsonIn, WSJsonOut},
    rest_filebrowser,
};
use actix::{
    prelude::{StreamHandler, *},
    Actor, ActorContext, AsyncContext, Context, Handler,
};
use actix_web::web::Json;
use actix_web_actors::ws;
use crossbeam::sync::WaitGroup;
use std::{string::String, sync::mpsc::Receiver, time::Duration, vec::Vec};

#[derive(Message)]
#[rtype(result = "()")]
pub struct MSyncStartup {}

#[derive(Message)]
#[rtype(result = "()")]
pub struct MDoneSyncStartup {}

/// Secure ActorSyncStartup by an Option
/// and consume it fast!
pub struct ActorSyncStartup {
    startup_sync: Option<WaitGroup>,
    inform_to: Addr<ActorWSServerMonitor>,
}
impl ActorSyncStartup {
    pub fn new(startup_sync: Option<WaitGroup>, inform_to: Addr<ActorWSServerMonitor>) -> Self {
        Self {
            startup_sync,
            inform_to,
        }
    }
}
impl Actor for ActorSyncStartup {
    type Context = Context<Self>;

    fn started(&mut self, _ctx: &mut Self::Context) {
        trace!("StartUpActor started");
    }
    fn stopped(&mut self, _ctx: &mut Self::Context) {
        trace!("StartUpActor stopped!");
    }
}
impl Handler<MSyncStartup> for ActorSyncStartup {
    type Result = ();

    fn handle(&mut self, _msg: MSyncStartup, _ctx: &mut Context<Self>) {
        //ctx.stop();
        if self.startup_sync.is_some() {
            let a = self.startup_sync.take();
            trace!("webui: waiting ui sync");
            a.unwrap().wait();
            trace!("webui: go");
            self.inform_to.do_send(MDoneSyncStartup {});
        } else {
            error!("no, this should not used again!");
        }
    }
}

#[derive(Message)]
#[rtype(result = "()")]
pub struct MRegisterWSClient {
    pub addr: Addr<ActorWebSocket>,
}
#[derive(Message)]
#[rtype(result = "()")]
pub struct MServerEvent {
    event: Json<WSJsonOut>,
}

/// Monitors all connected websockets,
/// and therefore distributes the internal incoming
/// messages.
pub struct ActorWSServerMonitor {
    pub receiver: Receiver<InternalUiMsg>,
    pub listeners: Vec<Addr<ActorWebSocket>>,
    pub paths: Vec<String>,
}
impl ActorWSServerMonitor {
    fn register(&mut self, listener: MRegisterWSClient) {
        trace!("register new listener");
        self.listeners.push(listener.addr);
    }
}

impl Actor for ActorWSServerMonitor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        trace!("server monitor got started");

        // when failing during startup this is important
        // todo: this is crap of course, polling in 20ms and try_recv on a receiver
        //       but for now it's fine!!! look at general Poll::, since libp2p uses
        //       just like actix here tokio, and Polling is used there!
        // fixme: part 2 ... cannot use actix functions to prevent run_interval to
        //        run even if actix is not correctly running, fix is at webui to
        //        not start ActorWSServerMonitor when there is no running http server
        //        (this happens when binding fails ... but it is already too late then)
        ctx.run_interval(Duration::from_millis(20), |act, _| {
            if let Ok(internal_message) = act.receiver.try_recv() {
                match internal_message {
                    InternalUiMsg::Terminate => actix::System::current().stop(),
                    _ => {
                        // inform all listeners
                        match json::convert_internal_message(&internal_message) {
                            Ok(response_json) => {
                                for ws in &act.listeners {
                                    ws.do_send(MServerEvent {
                                        event: Json(response_json.clone()),
                                    });
                                }
                            }
                            Err(attribute) => {
                                warn!(
                                    "No, we don't want the internal variable '{:?}' sent out!",
                                    attribute
                                );
                            }
                        }
                    }
                }
            }
        });
    }
}
impl Handler<MRegisterWSClient> for ActorWSServerMonitor {
    type Result = ();

    fn handle(&mut self, msg: MRegisterWSClient, _ctx: &mut Context<Self>) {
        self.register(msg);
    }
}

impl Handler<MDoneSyncStartup> for ActorWSServerMonitor {
    type Result = ();

    fn handle(&mut self, _msg: MDoneSyncStartup, _ctx: &mut Context<Self>) {
        trace!("sending init!");
        // todo: init shall be sent of course for each(!) new connecting websocket
        //       and this is going to ALL not matter if they did receive already.
        //       It can be a browser issues, since browser security prevents a lot of
        //       things, even to start cross-side javascript connection.
        let cloned_paths = self.paths.clone();
        for ws in &self.listeners {
            let answer = Json(json::generate_init_data(&cloned_paths.clone()));
            ws.do_send(MServerEvent { event: answer });
        }
    }
}

/// websocket connection is long running connection, it easier
/// to handle with an actor
pub struct ActorWebSocket {
    pub starter: Addr<ActorSyncStartup>,
}

impl Actor for ActorWebSocket {
    type Context = ws::WebsocketContext<Self>;

    /// Method is called on actor start. We start the heartbeat process here.
    fn started(&mut self, _ctx: &mut Self::Context) {
        trace!("ActorWebSocket started");
    }
    fn stopped(&mut self, _ctx: &mut Self::Context) {
        // On system stop this may or may not run
        warn!("shutting down whole actix-system");
        // todo: a single (!) websocket disconnect shuts down the whole application!!!
        //       in a multi connection program this should be deactivated (e.g. only
        //       per button or never) ... or a certain websocket (localhost ...??) should
        //       be the "master"
        actix::System::current().stop();
    }
}
impl Handler<MServerEvent> for ActorWebSocket {
    type Result = ();

    fn handle(&mut self, msg: MServerEvent, ctx: &mut Self::Context) {
        trace!("send: {}", msg.event.to_string());
        ctx.text(msg.event.to_string());
    }
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for ActorWebSocket {
    /// Handler for `ws::Message`
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        // process websocket messages
        match msg {
            Ok(good_message) => {
                match good_message {
                    ws::Message::Ping(msg) => {
                        ctx.pong(&msg);
                    }
                    ws::Message::Pong(_) => {}
                    ws::Message::Text(text) => {
                        let m = text.trim();
                        // /command
                        match json::convert_external_message(m) {
                            Ok(incoming) => match incoming {
                                WSJsonIn::start => {
                                    trace!("ready from Browser received!");
                                    self.starter.do_send(MSyncStartup {})
                                }
                                WSJsonIn::rest_dir(dir_in) => {
                                    let nr = dir_in.nr;
                                    let path = dir_in.dir;
                                    trace!("REST request received!");
                                    let dir = rest_filebrowser::return_directory(path);
                                    let ustream = json::rest_dirs(nr, &dir);
                                    ctx.text(ustream.to_string());
                                }
                            },
                            Err(wrong_message) => {
                                error!("received wrong message: {}", wrong_message);
                            }
                        }
                    }
                    ws::Message::Binary(bin) => ctx.binary(bin),
                    ws::Message::Close(_) => {
                        ctx.stop();
                    }
                    ws::Message::Nop => (),
                    ws::Message::Continuation(_) => (),
                }
            }
            Err(e) => warn!("message was not good {}", e),
        }
    }
}
<commit_msg>[security]  restrict REST path chooser to max path allowed<commit_after>///! All actors from webui are represented here
use super::{
    super::super::ctrl::InternalUiMsg,
    config::data::PATHS_MAX,
    json::{self, WSJsonIn, WSJsonOut},
    rest_filebrowser,
};
use actix::{
    prelude::{StreamHandler, *},
    Actor, ActorContext, AsyncContext, Context, Handler,
};
use actix_web::web::Json;
use actix_web_actors::ws;
use crossbeam::sync::WaitGroup;
use std::{string::String, sync::mpsc::Receiver, time::Duration, vec::Vec};

#[derive(Message)]
#[rtype(result = "()")]
pub struct MSyncStartup {}

#[derive(Message)]
#[rtype(result = "()")]
pub struct MDoneSyncStartup {}

/// Secure ActorSyncStartup by an Option
/// and consume it fast!
pub struct ActorSyncStartup {
    startup_sync: Option<WaitGroup>,
    inform_to: Addr<ActorWSServerMonitor>,
}
impl ActorSyncStartup {
    pub fn new(startup_sync: Option<WaitGroup>, inform_to: Addr<ActorWSServerMonitor>) -> Self {
        Self {
            startup_sync,
            inform_to,
        }
    }
}
impl Actor for ActorSyncStartup {
    type Context = Context<Self>;

    fn started(&mut self, _ctx: &mut Self::Context) {
        trace!("StartUpActor started");
    }
    fn stopped(&mut self, _ctx: &mut Self::Context) {
        trace!("StartUpActor stopped!");
    }
}
impl Handler<MSyncStartup> for ActorSyncStartup {
    type Result = ();

    fn handle(&mut self, _msg: MSyncStartup, _ctx: &mut Context<Self>) {
        //ctx.stop();
        if self.startup_sync.is_some() {
            let a = self.startup_sync.take();
            trace!("webui: waiting ui sync");
            a.unwrap().wait();
            trace!("webui: go");
            self.inform_to.do_send(MDoneSyncStartup {});
        } else {
            error!("no, this should not used again!");
        }
    }
}

#[derive(Message)]
#[rtype(result = "()")]
pub struct MRegisterWSClient {
    pub addr: Addr<ActorWebSocket>,
}
#[derive(Message)]
#[rtype(result = "()")]
pub struct MServerEvent {
    event: Json<WSJsonOut>,
}

/// Monitors all connected websockets,
/// and therefore distributes the internal incoming
/// messages.
pub struct ActorWSServerMonitor {
    pub receiver: Receiver<InternalUiMsg>,
    pub listeners: Vec<Addr<ActorWebSocket>>,
    pub paths: Vec<String>,
}
impl ActorWSServerMonitor {
    fn register(&mut self, listener: MRegisterWSClient) {
        trace!("register new listener");
        self.listeners.push(listener.addr);
    }
}

impl Actor for ActorWSServerMonitor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
        trace!("server monitor got started");

        // when failing during startup this is important
        // todo: this is crap of course, polling in 20ms and try_recv on a receiver
        //       but for now it's fine!!! look at general Poll::, since libp2p uses
        //       just like actix here tokio, and Polling is used there!
        // fixme: part 2 ... cannot use actix functions to prevent run_interval to
        //        run even if actix is not correctly running, fix is at webui to
        //        not start ActorWSServerMonitor when there is no running http server
        //        (this happens when binding fails ... but it is already too late then)
        ctx.run_interval(Duration::from_millis(20), |act, _| {
            if let Ok(internal_message) = act.receiver.try_recv() {
                match internal_message {
                    InternalUiMsg::Terminate => actix::System::current().stop(),
                    _ => {
                        // inform all listeners
                        match json::convert_internal_message(&internal_message) {
                            Ok(response_json) => {
                                for ws in &act.listeners {
                                    ws.do_send(MServerEvent {
                                        event: Json(response_json.clone()),
                                    });
                                }
                            }
                            Err(attribute) => {
                                warn!(
                                    "No, we don't want the internal variable '{:?}' sent out!",
                                    attribute
                                );
                            }
                        }
                    }
                }
            }
        });
    }
}
impl Handler<MRegisterWSClient> for ActorWSServerMonitor {
    type Result = ();

    fn handle(&mut self, msg: MRegisterWSClient, _ctx: &mut Context<Self>) {
        self.register(msg);
    }
}

impl Handler<MDoneSyncStartup> for ActorWSServerMonitor {
    type Result = ();

    fn handle(&mut self, _msg: MDoneSyncStartup, _ctx: &mut Context<Self>) {
        trace!("sending init!");
        // todo: init shall be sent of course for each(!) new connecting websocket
        //       and this is going to ALL not matter if they did receive already.
        //       It can be a browser issues, since browser security prevents a lot of
        //       things, even to start cross-side javascript connection.
        let cloned_paths = self.paths.clone();
        for ws in &self.listeners {
            let answer = Json(json::generate_init_data(&cloned_paths.clone()));
            ws.do_send(MServerEvent { event: answer });
        }
    }
}

/// websocket connection is long running connection, it easier
/// to handle with an actor
pub struct ActorWebSocket {
    pub starter: Addr<ActorSyncStartup>,
}

impl Actor for ActorWebSocket {
    type Context = ws::WebsocketContext<Self>;

    /// Method is called on actor start. We start the heartbeat process here.
    fn started(&mut self, _ctx: &mut Self::Context) {
        trace!("ActorWebSocket started");
    }
    fn stopped(&mut self, _ctx: &mut Self::Context) {
        // On system stop this may or may not run
        warn!("shutting down whole actix-system");
        // todo: a single (!) websocket disconnect shuts down the whole application!!!
        //       in a multi connection program this should be deactivated (e.g. only
        //       per button or never) ... or a certain websocket (localhost ...??) should
        //       be the "master"
        actix::System::current().stop();
    }
}
impl Handler<MServerEvent> for ActorWebSocket {
    type Result = ();

    fn handle(&mut self, msg: MServerEvent, ctx: &mut Self::Context) {
        trace!("send: {}", msg.event.to_string());
        ctx.text(msg.event.to_string());
    }
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for ActorWebSocket {
    /// Handler for `ws::Message`
    fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
        // process websocket messages
        match msg {
            Ok(good_message) => {
                match good_message {
                    ws::Message::Ping(msg) => {
                        ctx.pong(&msg);
                    }
                    ws::Message::Pong(_) => {}
                    ws::Message::Text(text) => {
                        let m = text.trim();
                        // /command
                        match json::convert_external_message(m) {
                            Ok(incoming) => match incoming {
                                WSJsonIn::start => {
                                    trace!("ready from Browser received!");
                                    self.starter.do_send(MSyncStartup {})
                                }
                                WSJsonIn::rest_dir(dir_in) => {
                                    let nr = dir_in.nr;
                                    if nr < PATHS_MAX {
                                        let path = dir_in.dir;
                                        trace!("REST request received!");
                                        let dir = rest_filebrowser::return_directory(path);
                                        let ustream = json::rest_dirs(nr, &dir);
                                        ctx.text(ustream.to_string());
                                    } else {
                                        error!("Some hacking ... there is a paths limit");
                                    }
                                }
                            },
                            Err(wrong_message) => {
                                error!("received wrong message: {}", wrong_message);
                            }
                        }
                    }
                    ws::Message::Binary(bin) => ctx.binary(bin),
                    ws::Message::Close(_) => {
                        ctx.stop();
                    }
                    ws::Message::Nop => (),
                    ws::Message::Continuation(_) => (),
                }
            }
            Err(e) => warn!("message was not good {}", e),
        }
    }
}
<|endoftext|>


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

use std::collections::HashSet;
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::DM;
use devicemapper::{DataBlocks, Sectors, Segment};
use devicemapper::LinearDev;
use devicemapper::{ThinPoolDev, ThinPoolStatus, ThinPoolWorkingStatus};
use time::now;
use uuid::Uuid;
use serde_json;

use super::super::consts::IEC::Mi;
use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, RenameAction, Redundancy};

use super::blockdevmgr::BlockDevMgr;
use super::device::wipe_sectors;
use super::dmdevice::{FlexRole, ThinPoolRole, format_flex_name, format_thinpool_name};
use super::filesystem::{StratFilesystem, FilesystemStatus};
use super::mdv::MetadataVol;
use super::metadata::MIN_MDA_SECTORS;
use super::serde_structs::{FlexDevsSave, PoolSave, Recordable, ThinPoolDevSave};

const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
const META_LOWATER: u64 = 512;
const DATA_LOWATER: DataBlocks = DataBlocks(512);

const INITIAL_META_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);
const INITIAL_DATA_SIZE: Sectors = Sectors(512 * Mi / SECTOR_SIZE as u64);
const INITIAL_MDV_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: Uuid,
    pub block_devs: BlockDevMgr,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
    mdv: MetadataVol,
}

impl StratPool {
    /// Initialize a Stratis Pool.
    /// 1. Initialize the block devices specified by paths.
    /// 2. Set up thinpool device to back filesystems.
    pub fn initialize(name: &str,
                      dm: &DM,
                      paths: &[&Path],
                      redundancy: Redundancy,
                      force: bool)
                      -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let mut block_mgr =
            try!(BlockDevMgr::initialize(&pool_uuid, paths, MIN_MDA_SECTORS, force));

        if block_mgr.avail_space() < StratPool::min_initial_size() {
            let avail_size = block_mgr.avail_space().bytes();
            try!(block_mgr.destroy_all());
            return Err(EngineError::Engine(ErrorEnum::Invalid,
                                           format!("Space on pool must be at least {} bytes, \
                                                   available space is only {} bytes",
                                                   StratPool::min_initial_size().bytes(),
                                                   avail_size)));

        }

        let meta_regions = block_mgr
            .alloc_space(INITIAL_META_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinMeta);
        let meta_dev = try!(LinearDev::new(&device_name, dm, meta_regions));

        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.devnode()), Sectors(0), INITIAL_META_SIZE));

        let data_regions = block_mgr
            .alloc_space(INITIAL_DATA_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinData);
        let data_dev = try!(LinearDev::new(&device_name, dm, data_regions));
        let length = try!(data_dev.size());

        let device_name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        // TODO Fix hard coded data blocksize and low water mark.
        let thinpool_dev = try!(ThinPoolDev::new(&device_name,
                                                 dm,
                                                 length,
                                                 DATA_BLOCK_SIZE,
                                                 DataBlocks(256000),
                                                 meta_dev,
                                                 data_dev));

        let mdv_regions = block_mgr
            .alloc_space(INITIAL_MDV_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::MetadataVolume);
        let mdv_dev = try!(LinearDev::new(&device_name, dm, mdv_regions));
        let mdv = try!(MetadataVol::initialize(&pool_uuid, mdv_dev));

        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: block_mgr,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
            mdv: mdv,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Minimum initial size for a pool.
    pub fn min_initial_size() -> Sectors {
        INITIAL_META_SIZE + INITIAL_DATA_SIZE + INITIAL_MDV_SIZE
    }

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&try!(self.record())));
        self.block_devs
            .save_state(&now().to_timespec(), data.as_bytes())
    }

    pub fn check(&mut self) -> () {
        let dm = DM::new().expect("Could not get DM handle");

        if let Err(e) = self.mdv.check() {
            error!("MDV error: {}", e);
            return;
        }

        let result = match self.thin_pool.status(&dm) {
            Ok(r) => r,
            Err(_) => {
                error!("Could not get thinpool status");
                // TODO: Take pool offline?
                return;
            }
        };

        match result {
            ThinPoolStatus::Good(wstatus, usage) => {
                match wstatus {
                    ThinPoolWorkingStatus::Good => {}
                    ThinPoolWorkingStatus::ReadOnly => {
                        // TODO: why is pool r/o and how do we get it
                        // rw again?
                    }
                    ThinPoolWorkingStatus::OutOfSpace => {
                        // TODO: Add more space if possible, or
                        // prevent further usage
                        // Should never happen -- we should be extending first!
                    }
                    ThinPoolWorkingStatus::NeedsCheck => {
                        // TODO: Take pool offline?
                        // TODO: run thin_check
                    }
                }

                if usage.used_meta > usage.total_meta - META_LOWATER {
                    // TODO: Extend meta device
                }

                if usage.used_data > usage.total_data - DATA_LOWATER {
                    // TODO: Extend data device
                }
            }
            ThinPoolStatus::Fail => {
                // TODO: Take pool offline?
                // TODO: Run thin_check
            }
        }

        for fs in &mut self.filesystems {
            match fs.check(&dm) {
                Ok(f_status) => {
                    if let FilesystemStatus::Failed = f_status {
                        // TODO: recover fs? (how?)
                    }
                }
                Err(_e) => error!("fs.check() failed"),
            }
        }
    }

    /// Teardown a pool.
    /// Take down the device mapper devices belonging to the pool.
    /// This method and destroy() must keep their DM teardown operations
    /// in sync.
    pub fn teardown(self) -> EngineResult<()> {
        // TODO: any necessary clean up of filesystems
        if !self.filesystems.is_empty() {
            return Err(EngineError::Engine(ErrorEnum::Busy,
                                           format!("May be unsynced files on device.")));
        }
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        Ok(())
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        // TODO: Roll back on filesystem initialization failure.
        let dm = try!(DM::new());
        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = try!(StratFilesystem::initialize(&self.pool_uuid,
                                                                  uuid,
                                                                  name,
                                                                  &dm,
                                                                  &mut self.thin_pool));
            try!(self.mdv.save_fs(&new_filesystem));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let bdev_paths = try!(self.block_devs.add(&self.pool_uuid, paths, force));
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(self) -> EngineResult<()> {
        // Ensure that DM teardown operations in this method are in sync
        // with operations in teardown().
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        try!(self.block_devs.destroy_all());

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        for fsid in fs_uuids {
            try!(self.mdv.rm_fs(fsid));
        }
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &FilesystemUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}

impl Recordable<PoolSave> for StratPool {
    fn record(&self) -> EngineResult<PoolSave> {

        let mapper = |seg: &Segment| -> EngineResult<(String, Sectors, Sectors)> {
            let bd = try!(self.block_devs
                     .get_by_device(seg.device)
                     .ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                format!("no block device found for device {:?}",
                                                        seg.device))));
            Ok((bd.uuid().simple().to_string(), seg.start, seg.length))
        };

        let mut meta_dev = vec![];
        for item in self.mdv.segments().iter().map(&mapper) {
            match item {
                Ok(seg) => meta_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        let mut thin_meta_dev = vec![];
        for item in self.thin_pool
                .meta_dev()
                .segments()
                .iter()
                .map(&mapper) {
            match item {
                Ok(seg) => thin_meta_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        let mut thin_data_dev = vec![];
        for item in self.thin_pool
                .data_dev()
                .segments()
                .iter()
                .map(&mapper) {
            match item {
                Ok(seg) => thin_data_dev.push(seg),
                Err(err) => return Err(err),
            }
        }

        Ok(PoolSave {
               name: self.name.clone(),
               block_devs: try!(self.block_devs.record()),
               flex_devs: FlexDevsSave {
                   meta_dev: meta_dev,
                   thin_meta_dev: thin_meta_dev,
                   thin_data_dev: thin_data_dev,
               },
               thinpool_dev: ThinPoolDevSave { data_block_size: *self.thin_pool.data_block_size() },
           })
    }
}
<commit_msg>Reduce unneeded syntax in StratPool::record()<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashSet;
use std::collections::hash_map::RandomState;
use std::iter::FromIterator;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;

use devicemapper::consts::SECTOR_SIZE;
use devicemapper::DM;
use devicemapper::{DataBlocks, Sectors, Segment};
use devicemapper::LinearDev;
use devicemapper::{ThinPoolDev, ThinPoolStatus, ThinPoolWorkingStatus};
use time::now;
use uuid::Uuid;
use serde_json;

use super::super::consts::IEC::Mi;
use super::super::engine::{Filesystem, HasName, HasUuid, Pool};
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::structures::Table;
use super::super::types::{FilesystemUuid, RenameAction, Redundancy};

use super::blockdevmgr::BlockDevMgr;
use super::device::wipe_sectors;
use super::dmdevice::{FlexRole, ThinPoolRole, format_flex_name, format_thinpool_name};
use super::filesystem::{StratFilesystem, FilesystemStatus};
use super::mdv::MetadataVol;
use super::metadata::MIN_MDA_SECTORS;
use super::serde_structs::{FlexDevsSave, PoolSave, Recordable, ThinPoolDevSave};

const DATA_BLOCK_SIZE: Sectors = Sectors(2048);
const META_LOWATER: u64 = 512;
const DATA_LOWATER: DataBlocks = DataBlocks(512);

const INITIAL_META_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);
const INITIAL_DATA_SIZE: Sectors = Sectors(512 * Mi / SECTOR_SIZE as u64);
const INITIAL_MDV_SIZE: Sectors = Sectors(16 * Mi / SECTOR_SIZE as u64);

#[derive(Debug)]
pub struct StratPool {
    name: String,
    pool_uuid: Uuid,
    pub block_devs: BlockDevMgr,
    pub filesystems: Table<StratFilesystem>,
    redundancy: Redundancy,
    thin_pool: ThinPoolDev,
    mdv: MetadataVol,
}

impl StratPool {
    /// Initialize a Stratis Pool.
    /// 1. Initialize the block devices specified by paths.
    /// 2. Set up thinpool device to back filesystems.
    pub fn initialize(name: &str,
                      dm: &DM,
                      paths: &[&Path],
                      redundancy: Redundancy,
                      force: bool)
                      -> EngineResult<StratPool> {
        let pool_uuid = Uuid::new_v4();

        let mut block_mgr =
            try!(BlockDevMgr::initialize(&pool_uuid, paths, MIN_MDA_SECTORS, force));

        if block_mgr.avail_space() < StratPool::min_initial_size() {
            let avail_size = block_mgr.avail_space().bytes();
            try!(block_mgr.destroy_all());
            return Err(EngineError::Engine(ErrorEnum::Invalid,
                                           format!("Space on pool must be at least {} bytes, \
                                                   available space is only {} bytes",
                                                   StratPool::min_initial_size().bytes(),
                                                   avail_size)));

        }

        let meta_regions = block_mgr
            .alloc_space(INITIAL_META_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinMeta);
        let meta_dev = try!(LinearDev::new(&device_name, dm, meta_regions));

        // When constructing a thin-pool, Stratis reserves the first N
        // sectors on a block device by creating a linear device with a
        // starting offset. DM writes the super block in the first block.
        // DM requires this first block to be zeros when the meta data for
        // the thin-pool is initially created. If we don't zero the
        // superblock DM issue error messages because it triggers code paths
        // that are trying to re-adopt the device with the attributes that
        // have been passed.
        try!(wipe_sectors(&try!(meta_dev.devnode()), Sectors(0), INITIAL_META_SIZE));

        let data_regions = block_mgr
            .alloc_space(INITIAL_DATA_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::ThinData);
        let data_dev = try!(LinearDev::new(&device_name, dm, data_regions));
        let length = try!(data_dev.size());

        let device_name = format_thinpool_name(&pool_uuid, ThinPoolRole::Pool);
        // TODO Fix hard coded data blocksize and low water mark.
        let thinpool_dev = try!(ThinPoolDev::new(&device_name,
                                                 dm,
                                                 length,
                                                 DATA_BLOCK_SIZE,
                                                 DataBlocks(256000),
                                                 meta_dev,
                                                 data_dev));

        let mdv_regions = block_mgr
            .alloc_space(INITIAL_MDV_SIZE)
            .expect("blockmgr must not fail, already checked for space");
        let device_name = format_flex_name(&pool_uuid, FlexRole::MetadataVolume);
        let mdv_dev = try!(LinearDev::new(&device_name, dm, mdv_regions));
        let mdv = try!(MetadataVol::initialize(&pool_uuid, mdv_dev));

        let mut pool = StratPool {
            name: name.to_owned(),
            pool_uuid: pool_uuid,
            block_devs: block_mgr,
            filesystems: Table::new(),
            redundancy: redundancy,
            thin_pool: thinpool_dev,
            mdv: mdv,
        };

        try!(pool.write_metadata());

        Ok(pool)
    }

    /// Minimum initial size for a pool.
    pub fn min_initial_size() -> Sectors {
        INITIAL_META_SIZE + INITIAL_DATA_SIZE + INITIAL_MDV_SIZE
    }

    // TODO: Check current time against global last updated, and use
    // alternate time value if earlier, as described in SWDD
    fn write_metadata(&mut self) -> EngineResult<()> {
        let data = try!(serde_json::to_string(&try!(self.record())));
        self.block_devs
            .save_state(&now().to_timespec(), data.as_bytes())
    }

    pub fn check(&mut self) -> () {
        let dm = DM::new().expect("Could not get DM handle");

        if let Err(e) = self.mdv.check() {
            error!("MDV error: {}", e);
            return;
        }

        let result = match self.thin_pool.status(&dm) {
            Ok(r) => r,
            Err(_) => {
                error!("Could not get thinpool status");
                // TODO: Take pool offline?
                return;
            }
        };

        match result {
            ThinPoolStatus::Good(wstatus, usage) => {
                match wstatus {
                    ThinPoolWorkingStatus::Good => {}
                    ThinPoolWorkingStatus::ReadOnly => {
                        // TODO: why is pool r/o and how do we get it
                        // rw again?
                    }
                    ThinPoolWorkingStatus::OutOfSpace => {
                        // TODO: Add more space if possible, or
                        // prevent further usage
                        // Should never happen -- we should be extending first!
                    }
                    ThinPoolWorkingStatus::NeedsCheck => {
                        // TODO: Take pool offline?
                        // TODO: run thin_check
                    }
                }

                if usage.used_meta > usage.total_meta - META_LOWATER {
                    // TODO: Extend meta device
                }

                if usage.used_data > usage.total_data - DATA_LOWATER {
                    // TODO: Extend data device
                }
            }
            ThinPoolStatus::Fail => {
                // TODO: Take pool offline?
                // TODO: Run thin_check
            }
        }

        for fs in &mut self.filesystems {
            match fs.check(&dm) {
                Ok(f_status) => {
                    if let FilesystemStatus::Failed = f_status {
                        // TODO: recover fs? (how?)
                    }
                }
                Err(_e) => error!("fs.check() failed"),
            }
        }
    }

    /// Teardown a pool.
    /// Take down the device mapper devices belonging to the pool.
    /// This method and destroy() must keep their DM teardown operations
    /// in sync.
    pub fn teardown(self) -> EngineResult<()> {
        // TODO: any necessary clean up of filesystems
        if !self.filesystems.is_empty() {
            return Err(EngineError::Engine(ErrorEnum::Busy,
                                           format!("May be unsynced files on device.")));
        }
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        Ok(())
    }
}

impl Pool for StratPool {
    fn create_filesystems<'a, 'b>(&'a mut self,
                                  specs: &[&'b str])
                                  -> EngineResult<Vec<(&'b str, FilesystemUuid)>> {
        let names: HashSet<_, RandomState> = HashSet::from_iter(specs);
        for name in names.iter() {
            if self.filesystems.contains_name(name) {
                return Err(EngineError::Engine(ErrorEnum::AlreadyExists, name.to_string()));
            }
        }

        // TODO: Roll back on filesystem initialization failure.
        let dm = try!(DM::new());
        let mut result = Vec::new();
        for name in names.iter() {
            let uuid = Uuid::new_v4();
            let new_filesystem = try!(StratFilesystem::initialize(&self.pool_uuid,
                                                                  uuid,
                                                                  name,
                                                                  &dm,
                                                                  &mut self.thin_pool));
            try!(self.mdv.save_fs(&new_filesystem));
            self.filesystems.insert(new_filesystem);
            result.push((**name, uuid));
        }

        Ok(result)
    }

    fn add_blockdevs(&mut self, paths: &[&Path], force: bool) -> EngineResult<Vec<PathBuf>> {
        let bdev_paths = try!(self.block_devs.add(&self.pool_uuid, paths, force));
        try!(self.write_metadata());
        Ok(bdev_paths)
    }

    fn destroy(self) -> EngineResult<()> {
        // Ensure that DM teardown operations in this method are in sync
        // with operations in teardown().
        let dm = try!(DM::new());
        try!(self.thin_pool.teardown(&dm));
        try!(self.mdv.teardown(&dm));
        try!(self.block_devs.destroy_all());

        Ok(())
    }

    fn destroy_filesystems<'a, 'b>(&'a mut self,
                                   fs_uuids: &[&'b FilesystemUuid])
                                   -> EngineResult<Vec<&'b FilesystemUuid>> {
        for fsid in fs_uuids {
            try!(self.mdv.rm_fs(fsid));
        }
        destroy_filesystems!{self; fs_uuids}
    }

    fn rename_filesystem(&mut self,
                         uuid: &FilesystemUuid,
                         new_name: &str)
                         -> EngineResult<RenameAction> {
        rename_filesystem!{self; uuid; new_name}
    }

    fn rename(&mut self, name: &str) {
        self.name = name.to_owned();
    }

    fn get_filesystem(&mut self, uuid: &FilesystemUuid) -> Option<&mut Filesystem> {
        get_filesystem!(self; uuid)
    }
}

impl HasUuid for StratPool {
    fn uuid(&self) -> &FilesystemUuid {
        &self.pool_uuid
    }
}

impl HasName for StratPool {
    fn name(&self) -> &str {
        &self.name
    }
}

impl Recordable<PoolSave> for StratPool {
    fn record(&self) -> EngineResult<PoolSave> {

        let mapper = |seg: &Segment| -> EngineResult<(String, Sectors, Sectors)> {
            let bd = try!(self.block_devs
                     .get_by_device(seg.device)
                     .ok_or(EngineError::Engine(ErrorEnum::NotFound,
                                                format!("no block device found for device {:?}",
                                                        seg.device))));
            Ok((bd.uuid().simple().to_string(), seg.start, seg.length))
        };

        let meta_dev = try!(self.mdv.segments().iter().map(&mapper).collect());

        let thin_meta_dev = try!(self.thin_pool
                                     .meta_dev()
                                     .segments()
                                     .iter()
                                     .map(&mapper)
                                     .collect());

        let thin_data_dev = try!(self.thin_pool
                                     .data_dev()
                                     .segments()
                                     .iter()
                                     .map(&mapper)
                                     .collect());

        Ok(PoolSave {
               name: self.name.clone(),
               block_devs: try!(self.block_devs.record()),
               flex_devs: FlexDevsSave {
                   meta_dev: meta_dev,
                   thin_meta_dev: thin_meta_dev,
                   thin_data_dev: thin_data_dev,
               },
               thinpool_dev: ThinPoolDevSave { data_block_size: *self.thin_pool.data_block_size() },
           })
    }
}
<|endoftext|>


<commit_before>use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};

/// A base target for AVR devices using the GNU toolchain.
///
/// Requires GNU avr-gcc and avr-binutils on the host system.
pub fn target(target_cpu: String) -> TargetResult {
    Ok(Target {
        arch: "avr".to_string(),
        data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(),
        llvm_target: "avr-unknown-unknown".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "16".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        target_os: "unknown".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        target_c_int_width: 16.to_string(),
        options: TargetOptions {
            cpu: target_cpu.clone(),
            exe_suffix: ".elf".to_string(),

            linker: Some("avr-gcc".to_owned()),
            dynamic_linking: false,
            executables: true,
            linker_is_gnu: true,
            has_rpath: false,
            position_independent_executables: false,
            eh_frame_header: false,
            pre_link_args: vec![(
                LinkerFlavor::Gcc,
                vec![
                    format!("-mmcu={}", target_cpu),
                    // We want to be able to strip as much executable code as possible
                    // from the linker command line, and this flag indicates to the
                    // linker that it can avoid linking in dynamic libraries that don't
                    // actually satisfy any symbols up to that point (as with many other
                    // resolutions the linker does). This option only applies to all
                    // following libraries so we're sure to pass it as one of the first
                    // arguments.
                    "-Wl,--as-needed".to_string(),
                ],
            )]
            .into_iter()
            .collect(),
            late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])]
                .into_iter()
                .collect(),
            ..TargetOptions::default()
        },
    })
}
<commit_msg>Rollup merge of #76364 - fusion-engineering-forks:avr-no-atomic, r=jonas-schievink<commit_after>use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};

/// A base target for AVR devices using the GNU toolchain.
///
/// Requires GNU avr-gcc and avr-binutils on the host system.
pub fn target(target_cpu: String) -> TargetResult {
    Ok(Target {
        arch: "avr".to_string(),
        data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(),
        llvm_target: "avr-unknown-unknown".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "16".to_string(),
        linker_flavor: LinkerFlavor::Gcc,
        target_os: "unknown".to_string(),
        target_env: "".to_string(),
        target_vendor: "unknown".to_string(),
        target_c_int_width: 16.to_string(),
        options: TargetOptions {
            cpu: target_cpu.clone(),
            exe_suffix: ".elf".to_string(),

            linker: Some("avr-gcc".to_owned()),
            dynamic_linking: false,
            executables: true,
            linker_is_gnu: true,
            has_rpath: false,
            position_independent_executables: false,
            eh_frame_header: false,
            pre_link_args: vec![(
                LinkerFlavor::Gcc,
                vec![
                    format!("-mmcu={}", target_cpu),
                    // We want to be able to strip as much executable code as possible
                    // from the linker command line, and this flag indicates to the
                    // linker that it can avoid linking in dynamic libraries that don't
                    // actually satisfy any symbols up to that point (as with many other
                    // resolutions the linker does). This option only applies to all
                    // following libraries so we're sure to pass it as one of the first
                    // arguments.
                    "-Wl,--as-needed".to_string(),
                ],
            )]
            .into_iter()
            .collect(),
            late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])]
                .into_iter()
                .collect(),
            max_atomic_width: Some(0),
            atomic_cas: false,
            ..TargetOptions::default()
        },
    })
}
<|endoftext|>


<commit_before>// Copyright 2019 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.

//! Building blocks for creating HTTP API of Rust services.

pub use crate::api::{Error, FutureResult, Result};

use exonum_crypto::{PublicKey, SecretKey};
use exonum_merkledb::{access::Prefixed, Snapshot};
use futures::IntoFuture;
use serde::{de::DeserializeOwned, Serialize};

use super::Broadcaster;
use crate::{
    api::{ApiBuilder, ApiScope},
    blockchain::{Blockchain, Schema as CoreSchema},
    runtime::{BlockchainData, InstanceDescriptor, InstanceId},
};

/// Provide the current blockchain state snapshot to API handlers.
///
/// This structure allows a service API handler to interact with the service instance
/// and other parts of the blockchain.
#[derive(Debug)]
pub struct ServiceApiState<'a> {
    /// Transaction broadcaster.
    broadcaster: Broadcaster<'a>,
    // TODO Think about avoiding of unnecessary snapshots creation. [ECR-3222]
    snapshot: Box<dyn Snapshot>,
}

impl<'a> ServiceApiState<'a> {
    /// Create service API state snapshot from the given blockchain and instance descriptor.
    pub fn from_api_context(blockchain: &'a Blockchain, instance: InstanceDescriptor<'a>) -> Self {
        Self {
            broadcaster: Broadcaster::new(
                instance,
                blockchain.service_keypair(),
                blockchain.sender(),
            ),
            snapshot: blockchain.snapshot(),
        }
    }

    /// Returns readonly access to blockchain data.
    pub fn data(&'a self) -> BlockchainData<&dyn Snapshot> {
        BlockchainData::new(&self.snapshot, self.instance())
    }

    /// Returns readonly access to the data of the executing service.
    pub fn service_data(&'a self) -> Prefixed<&dyn Snapshot> {
        self.data().for_executing_service()
    }

    /// Returns the service keypair of the node.
    pub fn service_keypair(&self) -> &(PublicKey, SecretKey) {
        self.broadcaster.keypair()
    }

    /// Returns information about the executing service.
    pub fn instance(&self) -> InstanceDescriptor<'_> {
        self.broadcaster.instance()
    }

    /// Returns a transaction broadcaster if the current node is a validator. If the node
    /// is not a validator, returns `None`.
    pub fn broadcaster(&self) -> Option<Broadcaster<'a>> {
        CoreSchema::new(&self.snapshot).validator_id(self.broadcaster.keypair().0)?;
        Some(self.broadcaster.clone())
    }

    /// Returns a transaction broadcaster regardless of the node status (validator or auditor).
    pub fn generic_broadcaster(&self) -> Broadcaster<'a> {
        self.broadcaster.clone()
    }
}

/// Exonum API builder for the concrete service API scope.
#[derive(Debug, Clone)]
pub struct ServiceApiScope {
    inner: ApiScope,
    blockchain: Blockchain,
    descriptor: (InstanceId, String),
}

impl ServiceApiScope {
    /// Create a new service API scope for the specified service instance.
    pub fn new(blockchain: Blockchain, instance: InstanceDescriptor<'_>) -> Self {
        Self {
            inner: ApiScope::new(),
            blockchain,
            descriptor: instance.into(),
        }
    }

    /// Add a readonly endpoint handler to the service API scope.
    ///
    /// In HTTP backends this type of endpoint corresponds to `GET` requests.
    /// [Read more.](../../../api/struct.ApiScope.html#endpoint)
    pub fn endpoint<Q, I, F, R>(&mut self, name: &'static str, handler: F) -> &mut Self
    where
        Q: DeserializeOwned + 'static,
        I: Serialize + 'static,
        F: Fn(&ServiceApiState<'_>, Q) -> R + 'static + Clone + Send + Sync,
        R: IntoFuture<Item = I, Error = crate::api::Error> + 'static,
    {
        let blockchain = self.blockchain.clone();
        let descriptor = self.descriptor.clone();
        self.inner
            .endpoint(name, move |query: Q| -> crate::api::FutureResult<I> {
                let state = ServiceApiState::from_api_context(
                    &blockchain,
                    InstanceDescriptor {
                        id: descriptor.0,
                        name: descriptor.1.as_ref(),
                    },
                );
                let result = handler(&state, query);
                Box::new(result.into_future())
            });
        self
    }

    /// Add an endpoint handler to the service API scope.
    ///
    /// In HTTP backends this type of endpoint corresponds to `POST` requests.
    /// [Read more.](../../../api/struct.ApiScope.html#endpoint_mut)
    pub fn endpoint_mut<Q, I, F, R>(&mut self, name: &'static str, handler: F) -> &mut Self
    where
        Q: DeserializeOwned + 'static,
        I: Serialize + 'static,
        F: Fn(&ServiceApiState<'_>, Q) -> R + 'static + Clone + Send + Sync,
        R: IntoFuture<Item = I, Error = crate::api::Error> + 'static,
    {
        let blockchain = self.blockchain.clone();
        let descriptor = self.descriptor.clone();
        self.inner
            .endpoint_mut(name, move |query: Q| -> crate::api::FutureResult<I> {
                let state = ServiceApiState::from_api_context(
                    &blockchain,
                    InstanceDescriptor {
                        id: descriptor.0,
                        name: descriptor.1.as_ref(),
                    },
                );
                let result = handler(&state, query);
                Box::new(result.into_future())
            });
        self
    }

    /// Return a mutable reference to the underlying web backend.
    pub fn web_backend(&mut self) -> &mut crate::api::backends::actix::ApiBuilder {
        self.inner.web_backend()
    }
}

/// Exonum service API builder which is used to add endpoints to the node API.
///
/// # Examples
///
/// The example below shows a common practice of the API implementation.
///
/// ```
/// use serde_derive::{Deserialize, Serialize};
///
/// use exonum::{
///     blockchain::Schema,
///     crypto::{self, Hash},
///     node::ExternalMessage,
///     runtime::rust::api::{self, ServiceApiBuilder, ServiceApiState},
/// };
/// use exonum_merkledb::ObjectHash;
///
/// // Declare a type which describes an API specification and implementation.
/// pub struct MyApi;
///
/// // Declare structures for requests and responses.
///
/// // For the web backend `MyQuery` will be deserialized from the `block_height={number}` string.
/// #[derive(Deserialize, Clone, Copy)]
/// pub struct MyQuery {
///     pub block_height: u64,
/// }
///
/// // For the web backend `BlockInfo` will be serialized into a JSON string.
/// #[derive(Serialize, Clone, Copy)]
/// pub struct BlockInfo {
///     pub hash: Hash,
/// }
///
/// // Create API handlers.
/// impl MyApi {
///     /// Immutable handler which returns a hash of the block at the given height.
///     pub fn block_hash(
///         state: &ServiceApiState,
///         query: MyQuery,
///     ) -> api::Result<Option<BlockInfo>> {
///         let schema = state.data().for_core();
///         Ok(schema
///             .block_hashes_by_height()
///             .get(query.block_height)
///             .map(|hash| BlockInfo { hash }))
///     }
///
///     /// Simple handler without any parameters.
///     pub fn ping(_state: &ServiceApiState, _query: ()) -> api::Result<()> {
///         Ok(())
///     }
///
///     /// You may also create asynchronous handlers for long requests.
///     pub fn async_operation(
///         _state: &ServiceApiState,
///         query: MyQuery,
///     ) -> api::FutureResult<Option<Hash>> {
///         Box::new(futures::lazy(move || {
///             Ok(Some(query.block_height.object_hash()))
///         }))
///     }
/// }
///
/// fn wire_api(builder: &mut ServiceApiBuilder) -> &mut ServiceApiBuilder {
///     // Add `MyApi` handlers to the corresponding builder.
///     builder
///         .public_scope()
///         .endpoint("v1/block_hash", MyApi::block_hash)
///         .endpoint("v1/async_operation", MyApi::async_operation);
///     // Add a mutable endpoint to the private API.
///     builder
///         .private_scope()
///         .endpoint("v1/ping", MyApi::ping);
///     builder
/// }
/// # fn main() {
/// #     use exonum::{blockchain::Blockchain, node::ApiSender, runtime::InstanceDescriptor};
/// #     use exonum_merkledb::TemporaryDB;
/// #     use futures::sync::mpsc;
/// #
/// #     let blockchain = Blockchain::new(
/// #         TemporaryDB::new(),
/// #         crypto::gen_keypair(),
/// #         ApiSender::new(mpsc::channel(0).0),
/// #     );
/// #     let mut builder = ServiceApiBuilder::new(
/// #         blockchain,
/// #         InstanceDescriptor {
/// #             id: 1100,
/// #             name: "example",
/// #         },
/// #     );
/// #     wire_api(&mut builder);
/// # }
/// ```
#[derive(Debug)]
pub struct ServiceApiBuilder {
    blockchain: Blockchain,
    public_scope: ServiceApiScope,
    private_scope: ServiceApiScope,
}

impl ServiceApiBuilder {
    /// Create a new service API builder for the specified service instance.
    #[doc(hidden)]
    pub fn new(blockchain: Blockchain, instance: InstanceDescriptor<'_>) -> Self {
        Self {
            blockchain: blockchain.clone(),
            public_scope: ServiceApiScope::new(blockchain.clone(), instance),
            private_scope: ServiceApiScope::new(blockchain, instance),
        }
    }

    /// Return a mutable reference to the public API scope builder.
    pub fn public_scope(&mut self) -> &mut ServiceApiScope {
        &mut self.public_scope
    }

    /// Return a mutable reference to the private API scope builder.
    pub fn private_scope(&mut self) -> &mut ServiceApiScope {
        &mut self.private_scope
    }

    /// Return a reference to the blockchain.
    pub fn blockchain(&self) -> &Blockchain {
        &self.blockchain
    }
}

impl From<ServiceApiBuilder> for ApiBuilder {
    fn from(inner: ServiceApiBuilder) -> Self {
        Self {
            public_scope: inner.public_scope.inner,
            private_scope: inner.private_scope.inner,
        }
    }
}
<commit_msg>Don't expose service secret key in ServiceApiState (#1593)<commit_after>// Copyright 2019 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.

//! Building blocks for creating HTTP API of Rust services.

pub use crate::api::{Error, FutureResult, Result};

use exonum_crypto::PublicKey;
use exonum_merkledb::{access::Prefixed, Snapshot};
use futures::IntoFuture;
use serde::{de::DeserializeOwned, Serialize};

use super::Broadcaster;
use crate::{
    api::{ApiBuilder, ApiScope},
    blockchain::{Blockchain, Schema as CoreSchema},
    runtime::{BlockchainData, InstanceDescriptor, InstanceId},
};

/// Provide the current blockchain state snapshot to API handlers.
///
/// This structure allows a service API handler to interact with the service instance
/// and other parts of the blockchain.
#[derive(Debug)]
pub struct ServiceApiState<'a> {
    /// Transaction broadcaster.
    broadcaster: Broadcaster<'a>,
    // TODO Think about avoiding of unnecessary snapshots creation. [ECR-3222]
    snapshot: Box<dyn Snapshot>,
}

impl<'a> ServiceApiState<'a> {
    /// Create service API state snapshot from the given blockchain and instance descriptor.
    pub fn from_api_context(blockchain: &'a Blockchain, instance: InstanceDescriptor<'a>) -> Self {
        Self {
            broadcaster: Broadcaster::new(
                instance,
                blockchain.service_keypair(),
                blockchain.sender(),
            ),
            snapshot: blockchain.snapshot(),
        }
    }

    /// Returns readonly access to blockchain data.
    pub fn data(&'a self) -> BlockchainData<&dyn Snapshot> {
        BlockchainData::new(&self.snapshot, self.instance())
    }

    /// Returns readonly access to the data of the executing service.
    pub fn service_data(&'a self) -> Prefixed<&dyn Snapshot> {
        self.data().for_executing_service()
    }

    /// Returns the service key of this node.
    pub fn service_key(&self) -> PublicKey {
        self.broadcaster.keypair().0
    }

    /// Returns information about the executing service.
    pub fn instance(&self) -> InstanceDescriptor<'_> {
        self.broadcaster.instance()
    }

    /// Returns a transaction broadcaster if the current node is a validator. If the node
    /// is not a validator, returns `None`.
    pub fn broadcaster(&self) -> Option<Broadcaster<'a>> {
        CoreSchema::new(&self.snapshot).validator_id(self.broadcaster.keypair().0)?;
        Some(self.broadcaster.clone())
    }

    /// Returns a transaction broadcaster regardless of the node status (validator or auditor).
    pub fn generic_broadcaster(&self) -> Broadcaster<'a> {
        self.broadcaster.clone()
    }
}

/// Exonum API builder for the concrete service API scope.
#[derive(Debug, Clone)]
pub struct ServiceApiScope {
    inner: ApiScope,
    blockchain: Blockchain,
    descriptor: (InstanceId, String),
}

impl ServiceApiScope {
    /// Create a new service API scope for the specified service instance.
    pub fn new(blockchain: Blockchain, instance: InstanceDescriptor<'_>) -> Self {
        Self {
            inner: ApiScope::new(),
            blockchain,
            descriptor: instance.into(),
        }
    }

    /// Add a readonly endpoint handler to the service API scope.
    ///
    /// In HTTP backends this type of endpoint corresponds to `GET` requests.
    /// [Read more.](../../../api/struct.ApiScope.html#endpoint)
    pub fn endpoint<Q, I, F, R>(&mut self, name: &'static str, handler: F) -> &mut Self
    where
        Q: DeserializeOwned + 'static,
        I: Serialize + 'static,
        F: Fn(&ServiceApiState<'_>, Q) -> R + 'static + Clone + Send + Sync,
        R: IntoFuture<Item = I, Error = crate::api::Error> + 'static,
    {
        let blockchain = self.blockchain.clone();
        let descriptor = self.descriptor.clone();
        self.inner
            .endpoint(name, move |query: Q| -> crate::api::FutureResult<I> {
                let state = ServiceApiState::from_api_context(
                    &blockchain,
                    InstanceDescriptor {
                        id: descriptor.0,
                        name: descriptor.1.as_ref(),
                    },
                );
                let result = handler(&state, query);
                Box::new(result.into_future())
            });
        self
    }

    /// Add an endpoint handler to the service API scope.
    ///
    /// In HTTP backends this type of endpoint corresponds to `POST` requests.
    /// [Read more.](../../../api/struct.ApiScope.html#endpoint_mut)
    pub fn endpoint_mut<Q, I, F, R>(&mut self, name: &'static str, handler: F) -> &mut Self
    where
        Q: DeserializeOwned + 'static,
        I: Serialize + 'static,
        F: Fn(&ServiceApiState<'_>, Q) -> R + 'static + Clone + Send + Sync,
        R: IntoFuture<Item = I, Error = crate::api::Error> + 'static,
    {
        let blockchain = self.blockchain.clone();
        let descriptor = self.descriptor.clone();
        self.inner
            .endpoint_mut(name, move |query: Q| -> crate::api::FutureResult<I> {
                let state = ServiceApiState::from_api_context(
                    &blockchain,
                    InstanceDescriptor {
                        id: descriptor.0,
                        name: descriptor.1.as_ref(),
                    },
                );
                let result = handler(&state, query);
                Box::new(result.into_future())
            });
        self
    }

    /// Return a mutable reference to the underlying web backend.
    pub fn web_backend(&mut self) -> &mut crate::api::backends::actix::ApiBuilder {
        self.inner.web_backend()
    }
}

/// Exonum service API builder which is used to add endpoints to the node API.
///
/// # Examples
///
/// The example below shows a common practice of the API implementation.
///
/// ```
/// use serde_derive::{Deserialize, Serialize};
///
/// use exonum::{
///     blockchain::Schema,
///     crypto::{self, Hash},
///     node::ExternalMessage,
///     runtime::rust::api::{self, ServiceApiBuilder, ServiceApiState},
/// };
/// use exonum_merkledb::ObjectHash;
///
/// // Declare a type which describes an API specification and implementation.
/// pub struct MyApi;
///
/// // Declare structures for requests and responses.
///
/// // For the web backend `MyQuery` will be deserialized from the `block_height={number}` string.
/// #[derive(Deserialize, Clone, Copy)]
/// pub struct MyQuery {
///     pub block_height: u64,
/// }
///
/// // For the web backend `BlockInfo` will be serialized into a JSON string.
/// #[derive(Serialize, Clone, Copy)]
/// pub struct BlockInfo {
///     pub hash: Hash,
/// }
///
/// // Create API handlers.
/// impl MyApi {
///     /// Immutable handler which returns a hash of the block at the given height.
///     pub fn block_hash(
///         state: &ServiceApiState,
///         query: MyQuery,
///     ) -> api::Result<Option<BlockInfo>> {
///         let schema = state.data().for_core();
///         Ok(schema
///             .block_hashes_by_height()
///             .get(query.block_height)
///             .map(|hash| BlockInfo { hash }))
///     }
///
///     /// Simple handler without any parameters.
///     pub fn ping(_state: &ServiceApiState, _query: ()) -> api::Result<()> {
///         Ok(())
///     }
///
///     /// You may also create asynchronous handlers for long requests.
///     pub fn async_operation(
///         _state: &ServiceApiState,
///         query: MyQuery,
///     ) -> api::FutureResult<Option<Hash>> {
///         Box::new(futures::lazy(move || {
///             Ok(Some(query.block_height.object_hash()))
///         }))
///     }
/// }
///
/// fn wire_api(builder: &mut ServiceApiBuilder) -> &mut ServiceApiBuilder {
///     // Add `MyApi` handlers to the corresponding builder.
///     builder
///         .public_scope()
///         .endpoint("v1/block_hash", MyApi::block_hash)
///         .endpoint("v1/async_operation", MyApi::async_operation);
///     // Add a mutable endpoint to the private API.
///     builder
///         .private_scope()
///         .endpoint("v1/ping", MyApi::ping);
///     builder
/// }
/// # fn main() {
/// #     use exonum::{blockchain::Blockchain, node::ApiSender, runtime::InstanceDescriptor};
/// #     use exonum_merkledb::TemporaryDB;
/// #     use futures::sync::mpsc;
/// #
/// #     let blockchain = Blockchain::new(
/// #         TemporaryDB::new(),
/// #         crypto::gen_keypair(),
/// #         ApiSender::new(mpsc::channel(0).0),
/// #     );
/// #     let mut builder = ServiceApiBuilder::new(
/// #         blockchain,
/// #         InstanceDescriptor {
/// #             id: 1100,
/// #             name: "example",
/// #         },
/// #     );
/// #     wire_api(&mut builder);
/// # }
/// ```
#[derive(Debug)]
pub struct ServiceApiBuilder {
    blockchain: Blockchain,
    public_scope: ServiceApiScope,
    private_scope: ServiceApiScope,
}

impl ServiceApiBuilder {
    /// Create a new service API builder for the specified service instance.
    #[doc(hidden)]
    pub fn new(blockchain: Blockchain, instance: InstanceDescriptor<'_>) -> Self {
        Self {
            blockchain: blockchain.clone(),
            public_scope: ServiceApiScope::new(blockchain.clone(), instance),
            private_scope: ServiceApiScope::new(blockchain, instance),
        }
    }

    /// Return a mutable reference to the public API scope builder.
    pub fn public_scope(&mut self) -> &mut ServiceApiScope {
        &mut self.public_scope
    }

    /// Return a mutable reference to the private API scope builder.
    pub fn private_scope(&mut self) -> &mut ServiceApiScope {
        &mut self.private_scope
    }

    /// Return a reference to the blockchain.
    pub fn blockchain(&self) -> &Blockchain {
        &self.blockchain
    }
}

impl From<ServiceApiBuilder> for ApiBuilder {
    fn from(inner: ServiceApiBuilder) -> Self {
        Self {
            public_scope: inner.public_scope.inner,
            private_scope: inner.private_scope.inner,
        }
    }
}
<|endoftext|>


<commit_before>extern crate serenity;

command!(clear(_context, msg, args) {
	if args.len() == 1 {
		let countdown: u64 = match args[0].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(countdown)) {
				let mut vec_id = Vec::new();
				for message in vec {
					vec_id.push(message.id);
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
	else if args.len() == 1 {
		let countdown: u64 = match args[0].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		let counter: u64 = match args[1].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		let full = countdown + counter;
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(full)) {
				let mut vec_id = Vec::new();
				let mut i = 0;
				for message in vec {
					while i < countdown {
						vec_id.push(message.id);
					}
					i += 1;
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
});
<commit_msg>New functionality for clear command<commit_after>extern crate serenity;

command!(clear(_context, msg, args) {
	if args.len() == 1 {
		let countdown: u64 = match args[0].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(countdown)) {
				let mut vec_id = Vec::new();
				for message in vec {
					vec_id.push(message.id);
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
	else if args.len() == 1 {
		let countdown: u64 = match args[0].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		let counter: u64 = match args[1].parse() {
			Ok(val)  => val,
			Err(_err) => 0,
		};
		let full = countdown + counter;
		for vec in msg.channel_id.messages(|g| g.before(msg.id).limit(full)) {
				let mut vec_id = Vec::new();
				let mut i = 0;
				while i < countdown {
					for message in vec {
						vec_id.push(message.id);
						i += 1;
					}
				}
				vec_id.push(msg.id);
				match msg.channel_id.delete_messages(vec_id.as_slice()) {
					Ok(val)  => val,
					Err(_err) => (),
				};
		}
		let _=msg.channel_id.send_message(|m| m.content(format!("Deleted {} messages",countdown)));
	}
});
<|endoftext|>


<commit_before>use error::Result;
use postgres::Connection;
use std::collections::BTreeMap;
use std::time::Duration;

const DEFAULT_MEMORY_LIMIT: usize = 3 * 1024 * 1024 * 1024; // 3 GB
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(15 * 60); // 15 minutes
const DEFAULT_NETWORKING: bool = false;
const DEFAULT_MAX_LOG_SIZE: usize = 100 * 1024; // 100 KB

pub(crate) struct Limits {
    memory: usize,
    timeout: Duration,
    networking: bool,
    max_log_size: usize,
}

impl Default for Limits {
    fn default() -> Self {
        Self {
            memory: DEFAULT_MEMORY_LIMIT,
            timeout: DEFAULT_TIMEOUT,
            networking: DEFAULT_NETWORKING,
            max_log_size: DEFAULT_MAX_LOG_SIZE,
        }
    }
}

impl Limits {
    pub(crate) fn for_crate(conn: &Connection, name: &str) -> Result<Self> {
        let mut limits = Self::default();

        let res = conn.query(
            "SELECT * FROM sandbox_overrides WHERE crate_name = $1;",
            &[&name],
        )?;
        if !res.is_empty() {
            let row = res.get(0);
            if let Some(memory) = row.get::<_, Option<i32>>("max_memory_bytes") {
                limits.memory = memory as usize;
            }
            if let Some(timeout) = row.get::<_, Option<i32>>("timeout_seconds") {
                limits.timeout = Duration::from_secs(timeout as u64);
            }
        }

        Ok(limits)
    }

    pub(crate) fn memory(&self) -> usize {
        self.memory
    }

    pub(crate) fn timeout(&self) -> Duration {
        self.timeout
    }

    pub(crate) fn networking(&self) -> bool {
        self.networking
    }

    pub(crate) fn max_log_size(&self) -> usize {
        self.max_log_size
    }

    pub(crate) fn for_website(&self) -> BTreeMap<String, String> {
        let time_scale = |v| scale(v, 60, &["seconds", "minutes", "hours"]);
        let size_scale = |v| scale(v, 1024, &["bytes", "KB", "MB", "GB"]);

        let mut res = BTreeMap::new();
        res.insert("Available RAM".into(), size_scale(self.memory));
        res.insert(
            "Maximum rustdoc execution time".into(),
            time_scale(self.timeout.as_secs() as usize),
        );
        res.insert("Maximum size of a build log".into(), size_scale(self.max_log_size));
        if self.networking {
            res.insert("Network access".into(), "allowed".into());
        } else {
            res.insert("Network access".into(), "blocked".into());
        }
        res
    }
}

fn scale(mut value: usize, interval: usize, labels: &[&str]) -> String {
    let mut chosen_label = &labels[0];
    for label in &labels[1..] {
        if (value as f64) / (interval as f64) >= 1.0 {
            chosen_label = label;
            value = value / interval;
        } else {
            break;
        }
    }
    format!("{} {}", value, chosen_label)
}
<commit_msg>inline limits constants directly into the default impl<commit_after>use error::Result;
use postgres::Connection;
use std::collections::BTreeMap;
use std::time::Duration;

pub(crate) struct Limits {
    memory: usize,
    timeout: Duration,
    networking: bool,
    max_log_size: usize,
}

impl Default for Limits {
    fn default() -> Self {
        Self {
            memory: 3 * 1024 * 1024 * 1024,  // 3 GB
            timeout: Duration::from_secs(15 * 60),  // 15 minutes
            networking: false,
            max_log_size: 100 * 1024, // 100 KB
        }
    }
}

impl Limits {
    pub(crate) fn for_crate(conn: &Connection, name: &str) -> Result<Self> {
        let mut limits = Self::default();

        let res = conn.query(
            "SELECT * FROM sandbox_overrides WHERE crate_name = $1;",
            &[&name],
        )?;
        if !res.is_empty() {
            let row = res.get(0);
            if let Some(memory) = row.get::<_, Option<i32>>("max_memory_bytes") {
                limits.memory = memory as usize;
            }
            if let Some(timeout) = row.get::<_, Option<i32>>("timeout_seconds") {
                limits.timeout = Duration::from_secs(timeout as u64);
            }
        }

        Ok(limits)
    }

    pub(crate) fn memory(&self) -> usize {
        self.memory
    }

    pub(crate) fn timeout(&self) -> Duration {
        self.timeout
    }

    pub(crate) fn networking(&self) -> bool {
        self.networking
    }

    pub(crate) fn max_log_size(&self) -> usize {
        self.max_log_size
    }

    pub(crate) fn for_website(&self) -> BTreeMap<String, String> {
        let time_scale = |v| scale(v, 60, &["seconds", "minutes", "hours"]);
        let size_scale = |v| scale(v, 1024, &["bytes", "KB", "MB", "GB"]);

        let mut res = BTreeMap::new();
        res.insert("Available RAM".into(), size_scale(self.memory));
        res.insert(
            "Maximum rustdoc execution time".into(),
            time_scale(self.timeout.as_secs() as usize),
        );
        res.insert("Maximum size of a build log".into(), size_scale(self.max_log_size));
        if self.networking {
            res.insert("Network access".into(), "allowed".into());
        } else {
            res.insert("Network access".into(), "blocked".into());
        }
        res
    }
}

fn scale(mut value: usize, interval: usize, labels: &[&str]) -> String {
    let mut chosen_label = &labels[0];
    for label in &labels[1..] {
        if (value as f64) / (interval as f64) >= 1.0 {
            chosen_label = label;
            value = value / interval;
        } else {
            break;
        }
    }
    format!("{} {}", value, chosen_label)
}
<|endoftext|>