<commit_before>#[allow(unused_imports)] // right now just used in feature flag
use core;
use alloc::{SliceWrapper, Allocator, SliceWrapperMut};
#[derive(Debug,Copy,Clone,Default)]
pub struct BlockSwitch(pub u8);
// Commands that can instantiate as a no-op should implement this.
pub trait Nop<T> {
    fn nop() -> T;
}

impl BlockSwitch {
    #[inline(always)]
    pub fn new(block_type: u8) -> Self {
        BlockSwitch(block_type)
    }
    #[inline(always)]
    pub fn block_type(&self) -> u8 {
        self.0
    }
}

#[derive(Debug,Copy,Clone,Default)]
pub struct LiteralBlockSwitch(pub BlockSwitch, pub u8);

impl LiteralBlockSwitch {
    pub fn new(block_type: u8, stride: u8) -> Self {
        LiteralBlockSwitch(BlockSwitch::new(block_type), stride)
    }
    #[inline(always)]
    pub fn block_type(&self) -> u8 {
        self.0.block_type()
    }
    #[inline(always)]
    pub fn stride(&self) -> u8 {
        self.1
    }
    #[inline(always)]
    pub fn update_stride(&mut self, new_stride: u8) {
        self.1 = new_stride;
    }
}

pub const LITERAL_PREDICTION_MODE_SIGN: u8 = 3;
pub const LITERAL_PREDICTION_MODE_UTF8: u8 = 2;
pub const LITERAL_PREDICTION_MODE_MSB6: u8 = 1;
pub const LITERAL_PREDICTION_MODE_LSB6: u8 = 0;

#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct LiteralPredictionModeNibble(pub u8);

impl LiteralPredictionModeNibble {
    #[inline(always)]
    pub fn new(prediction_mode: u8) -> Result<Self, ()> {
        if prediction_mode < 16 {
            return Ok(LiteralPredictionModeNibble(prediction_mode));
        }
        return Err(());
    }
    #[inline(always)]
    pub fn prediction_mode(&self) -> u8 {
        self.0
    }
    #[inline(always)]
    pub fn signed() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_SIGN)
    }
    #[inline(always)]
    pub fn utf8() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_UTF8)
    }
    #[inline(always)]
    pub fn msb6() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_MSB6)
    }
    #[inline(always)]
    pub fn lsb6() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_LSB6)
    }
}
#[derive(Debug)]
pub struct PredictionModeContextMap<SliceType:SliceWrapper<u8>> {
    pub literal_prediction_mode: LiteralPredictionModeNibble,
    pub literal_context_map: SliceType,
    pub distance_context_map: SliceType,
}
impl<SliceType:SliceWrapper<u8>+Clone> Clone for PredictionModeContextMap<SliceType> {
    fn clone(&self) -> PredictionModeContextMap<SliceType>{
        PredictionModeContextMap::<SliceType>{
            literal_prediction_mode:self.literal_prediction_mode,
            literal_context_map:self.literal_context_map.clone(),
            distance_context_map:self.distance_context_map.clone(),
        }
    }
}

impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for PredictionModeContextMap<SliceType> {
}

#[derive(Debug,Clone,Copy)]
pub struct CopyCommand {
    pub distance: u32,
    pub num_bytes: u32,
}

impl Nop<CopyCommand> for CopyCommand {
    #[inline(always)]
    fn nop() -> Self {
        CopyCommand {
            distance: 1,
            num_bytes: 0
        }
    }
}

#[derive(Debug,Clone,Copy)]
pub struct DictCommand {
    pub word_size: u8,
    pub transform: u8,
    pub final_size: u8,
    pub empty: u8,
    pub word_id: u32,
}

impl Nop<DictCommand> for DictCommand {
    #[inline(always)]
    fn nop() -> Self {
        DictCommand {
            word_size: 0,
            transform: 0,
            final_size: 0,
            empty: 1,
            word_id: 0
        }
    }
}

#[derive(Debug)]
#[cfg(not(feature="external-literal-probability"))]
pub struct FeatureFlagSliceType<SliceType:SliceWrapper<u8> >(core::marker::PhantomData<*const SliceType>);

#[cfg(not(feature="external-literal-probability"))]
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
   fn slice(&self) -> &[u8] {
       &[]
   }
}

#[cfg(not(feature="external-literal-probability"))]
impl<SliceType:SliceWrapper<u8>+Default> Default for FeatureFlagSliceType<SliceType> {
    fn default() -> Self {
        FeatureFlagSliceType::<SliceType>(core::marker::PhantomData::<*const SliceType>::default())
    }
}

#[derive(Debug)]
#[cfg(feature="external-literal-probability")]
pub struct FeatureFlagSliceType<SliceType:SliceWrapper<u8> >(pub SliceType);

#[cfg(feature="external-literal-probability")]
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
    #[inline(always)]
   fn slice(&self) -> &[u8] {
       self.0.slice()
   }
}

#[cfg(feature="external-literal-probability")]
impl<SliceType:SliceWrapper<u8>+Default> Default for FeatureFlagSliceType<SliceType> {
    #[inline(always)]
    fn default() -> Self {
        FeatureFlagSliceType::<SliceType>(SliceType::default())
    }
}

impl<SliceType:SliceWrapper<u8>+Clone> Clone for FeatureFlagSliceType<SliceType> {
    #[inline(always)]
    fn clone(&self) -> Self {
       FeatureFlagSliceType::<SliceType>(self.0.clone())
    }
}
impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for FeatureFlagSliceType<SliceType> {
}

#[derive(Debug)]
pub struct LiteralCommand<SliceType:SliceWrapper<u8>> {
    pub data: SliceType,
    pub prob: FeatureFlagSliceType<SliceType>
}
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for LiteralCommand<SliceType> {
    #[inline(always)]
    fn slice(&self) -> &[u8] {
        self.data.slice()
    }
}
impl<SliceType:SliceWrapper<u8>+SliceWrapperMut<u8>> SliceWrapperMut<u8> for LiteralCommand<SliceType> {
    #[inline(always)]
    fn slice_mut(&mut self) -> &mut [u8] {
        self.data.slice_mut()
    }
}

impl<SliceType:SliceWrapper<u8>+Default> Nop<LiteralCommand<SliceType>> for LiteralCommand<SliceType> {
    #[inline(always)]
    fn nop() -> Self {
        LiteralCommand {
            data: SliceType::default(),
            prob: FeatureFlagSliceType::<SliceType>::default(),
        }
    }
}
impl<SliceType:SliceWrapper<u8>+Clone> Clone for LiteralCommand<SliceType> {
    #[inline(always)]
    fn clone(&self) -> LiteralCommand<SliceType>{
        LiteralCommand::<SliceType>{data:self.data.clone(), prob:self.prob.clone()}
    }
}
impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for LiteralCommand<SliceType> {
}

#[derive(Debug)]
pub struct RandLiteralCommand<SliceType:SliceWrapper<u8>> {
    pub data: SliceType,
}
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn slice(&self) -> &[u8] {
        self.data.slice()
    }
}
impl<SliceType:SliceWrapper<u8>+SliceWrapperMut<u8>> SliceWrapperMut<u8> for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn slice_mut(&mut self) -> &mut [u8] {
        self.data.slice_mut()
    }
}

impl<SliceType:SliceWrapper<u8>+Default> Nop<RandLiteralCommand<SliceType>> for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn nop() -> Self {
        RandLiteralCommand {
            data: SliceType::default(),
        }
    }
}
impl<SliceType:SliceWrapper<u8>+Clone> Clone for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn clone(&self) -> RandLiteralCommand<SliceType>{
        RandLiteralCommand::<SliceType>{data:self.data.clone()}
    }
}
impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for RandLiteralCommand<SliceType> {
}

#[derive(Debug)]
pub enum Command<SliceType:SliceWrapper<u8> > {
    Copy(CopyCommand),
    Dict(DictCommand),
    Literal(LiteralCommand<SliceType>),
    RandLiteral(RandLiteralCommand<SliceType>),
    BlockSwitchCommand(BlockSwitch),
    BlockSwitchLiteral(LiteralBlockSwitch),
    BlockSwitchDistance(BlockSwitch),
    PredictionMode(PredictionModeContextMap<SliceType>),
}
impl<SliceType:SliceWrapper<u8>+Default> Command<SliceType> {
    pub fn free_array<F>(&mut self, apply_func: &mut F) where F: FnMut(SliceType) {
       match self {
          &mut Command::Literal(ref mut lit) => {
             apply_func(core::mem::replace(&mut lit.data, SliceType::default()))
          },
          &mut Command::RandLiteral(ref mut lit) => {
             apply_func(core::mem::replace(&mut lit.data, SliceType::default()))
          },
          &mut Command::PredictionMode(ref mut pm) => {
             apply_func(core::mem::replace(&mut pm.literal_context_map, SliceType::default()));
             apply_func(core::mem::replace(&mut pm.distance_context_map, SliceType::default()));
          },
          _ => {},
       }
    }
}

impl<SliceType:SliceWrapper<u8>> Default for Command<SliceType> {
    #[inline(always)]
    fn default() -> Self {
        Command::<SliceType>::nop()
    }
}

impl<SliceType:SliceWrapper<u8>> Nop<Command<SliceType>> for Command<SliceType> {
    #[inline(always)]
    fn nop() -> Command<SliceType> {
        Command::Copy(CopyCommand::nop())
    }
}

impl<SliceType:SliceWrapper<u8>+Clone> Clone for Command<SliceType> {
    fn clone(&self) -> Command<SliceType>{
        match self {
            &Command::Copy(ref copy) => Command::Copy(copy.clone()),
            &Command::Dict(ref dict) => Command::Dict(dict.clone()),
            &Command::Literal(ref literal) => Command::Literal(literal.clone()),
            &Command::RandLiteral(ref literal) => Command::RandLiteral(literal.clone()),
            &Command::BlockSwitchCommand(ref switch) => Command::BlockSwitchCommand(switch.clone()),
            &Command::BlockSwitchLiteral(ref switch) => Command::BlockSwitchLiteral(switch.clone()),
            &Command::BlockSwitchDistance(ref switch) => Command::BlockSwitchDistance(switch.clone()),
            &Command::PredictionMode(ref pm) => Command::PredictionMode(pm.clone()),
        }
    }
}

impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for Command<SliceType> {
}

pub fn free_cmd<SliceTypeAllocator:Allocator<u8>> (xself: &mut Command<SliceTypeAllocator::AllocatedMemory>, m8: &mut SliceTypeAllocator) {
       match xself {
          &mut Command::Literal(ref mut lit) => {
             m8.free_cell(core::mem::replace(&mut lit.data, SliceTypeAllocator::AllocatedMemory::default()))
          },
          &mut Command::RandLiteral(ref mut lit) => {
             m8.free_cell(core::mem::replace(&mut lit.data, SliceTypeAllocator::AllocatedMemory::default()))
          },
          &mut Command::PredictionMode(ref mut pm) => {
             m8.free_cell(core::mem::replace(&mut pm.literal_context_map, SliceTypeAllocator::AllocatedMemory::default()));
             m8.free_cell(core::mem::replace(&mut pm.distance_context_map, SliceTypeAllocator::AllocatedMemory::default()));
          },
          _ => {},
    }
}
<commit_msg>make the switch statement deal with each possible input separately, so that we are notified of the code change when adding new types<commit_after>#[allow(unused_imports)] // right now just used in feature flag
use core;
use alloc::{SliceWrapper, Allocator, SliceWrapperMut};
#[derive(Debug,Copy,Clone,Default)]
pub struct BlockSwitch(pub u8);
// Commands that can instantiate as a no-op should implement this.
pub trait Nop<T> {
    fn nop() -> T;
}

impl BlockSwitch {
    #[inline(always)]
    pub fn new(block_type: u8) -> Self {
        BlockSwitch(block_type)
    }
    #[inline(always)]
    pub fn block_type(&self) -> u8 {
        self.0
    }
}

#[derive(Debug,Copy,Clone,Default)]
pub struct LiteralBlockSwitch(pub BlockSwitch, pub u8);

impl LiteralBlockSwitch {
    pub fn new(block_type: u8, stride: u8) -> Self {
        LiteralBlockSwitch(BlockSwitch::new(block_type), stride)
    }
    #[inline(always)]
    pub fn block_type(&self) -> u8 {
        self.0.block_type()
    }
    #[inline(always)]
    pub fn stride(&self) -> u8 {
        self.1
    }
    #[inline(always)]
    pub fn update_stride(&mut self, new_stride: u8) {
        self.1 = new_stride;
    }
}

pub const LITERAL_PREDICTION_MODE_SIGN: u8 = 3;
pub const LITERAL_PREDICTION_MODE_UTF8: u8 = 2;
pub const LITERAL_PREDICTION_MODE_MSB6: u8 = 1;
pub const LITERAL_PREDICTION_MODE_LSB6: u8 = 0;

#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct LiteralPredictionModeNibble(pub u8);

impl LiteralPredictionModeNibble {
    #[inline(always)]
    pub fn new(prediction_mode: u8) -> Result<Self, ()> {
        if prediction_mode < 16 {
            return Ok(LiteralPredictionModeNibble(prediction_mode));
        }
        return Err(());
    }
    #[inline(always)]
    pub fn prediction_mode(&self) -> u8 {
        self.0
    }
    #[inline(always)]
    pub fn signed() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_SIGN)
    }
    #[inline(always)]
    pub fn utf8() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_UTF8)
    }
    #[inline(always)]
    pub fn msb6() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_MSB6)
    }
    #[inline(always)]
    pub fn lsb6() -> Self {
        LiteralPredictionModeNibble(LITERAL_PREDICTION_MODE_LSB6)
    }
}
#[derive(Debug)]
pub struct PredictionModeContextMap<SliceType:SliceWrapper<u8>> {
    pub literal_prediction_mode: LiteralPredictionModeNibble,
    pub literal_context_map: SliceType,
    pub distance_context_map: SliceType,
}
impl<SliceType:SliceWrapper<u8>+Clone> Clone for PredictionModeContextMap<SliceType> {
    fn clone(&self) -> PredictionModeContextMap<SliceType>{
        PredictionModeContextMap::<SliceType>{
            literal_prediction_mode:self.literal_prediction_mode,
            literal_context_map:self.literal_context_map.clone(),
            distance_context_map:self.distance_context_map.clone(),
        }
    }
}

impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for PredictionModeContextMap<SliceType> {
}

#[derive(Debug,Clone,Copy)]
pub struct CopyCommand {
    pub distance: u32,
    pub num_bytes: u32,
}

impl Nop<CopyCommand> for CopyCommand {
    #[inline(always)]
    fn nop() -> Self {
        CopyCommand {
            distance: 1,
            num_bytes: 0
        }
    }
}

#[derive(Debug,Clone,Copy)]
pub struct DictCommand {
    pub word_size: u8,
    pub transform: u8,
    pub final_size: u8,
    pub empty: u8,
    pub word_id: u32,
}

impl Nop<DictCommand> for DictCommand {
    #[inline(always)]
    fn nop() -> Self {
        DictCommand {
            word_size: 0,
            transform: 0,
            final_size: 0,
            empty: 1,
            word_id: 0
        }
    }
}

#[derive(Debug)]
#[cfg(not(feature="external-literal-probability"))]
pub struct FeatureFlagSliceType<SliceType:SliceWrapper<u8> >(core::marker::PhantomData<*const SliceType>);

#[cfg(not(feature="external-literal-probability"))]
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
   fn slice(&self) -> &[u8] {
       &[]
   }
}

#[cfg(not(feature="external-literal-probability"))]
impl<SliceType:SliceWrapper<u8>+Default> Default for FeatureFlagSliceType<SliceType> {
    fn default() -> Self {
        FeatureFlagSliceType::<SliceType>(core::marker::PhantomData::<*const SliceType>::default())
    }
}

#[derive(Debug)]
#[cfg(feature="external-literal-probability")]
pub struct FeatureFlagSliceType<SliceType:SliceWrapper<u8> >(pub SliceType);

#[cfg(feature="external-literal-probability")]
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for FeatureFlagSliceType<SliceType> {
    #[inline(always)]
   fn slice(&self) -> &[u8] {
       self.0.slice()
   }
}

#[cfg(feature="external-literal-probability")]
impl<SliceType:SliceWrapper<u8>+Default> Default for FeatureFlagSliceType<SliceType> {
    #[inline(always)]
    fn default() -> Self {
        FeatureFlagSliceType::<SliceType>(SliceType::default())
    }
}

impl<SliceType:SliceWrapper<u8>+Clone> Clone for FeatureFlagSliceType<SliceType> {
    #[inline(always)]
    fn clone(&self) -> Self {
       FeatureFlagSliceType::<SliceType>(self.0.clone())
    }
}
impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for FeatureFlagSliceType<SliceType> {
}

#[derive(Debug)]
pub struct LiteralCommand<SliceType:SliceWrapper<u8>> {
    pub data: SliceType,
    pub prob: FeatureFlagSliceType<SliceType>
}
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for LiteralCommand<SliceType> {
    #[inline(always)]
    fn slice(&self) -> &[u8] {
        self.data.slice()
    }
}
impl<SliceType:SliceWrapper<u8>+SliceWrapperMut<u8>> SliceWrapperMut<u8> for LiteralCommand<SliceType> {
    #[inline(always)]
    fn slice_mut(&mut self) -> &mut [u8] {
        self.data.slice_mut()
    }
}

impl<SliceType:SliceWrapper<u8>+Default> Nop<LiteralCommand<SliceType>> for LiteralCommand<SliceType> {
    #[inline(always)]
    fn nop() -> Self {
        LiteralCommand {
            data: SliceType::default(),
            prob: FeatureFlagSliceType::<SliceType>::default(),
        }
    }
}
impl<SliceType:SliceWrapper<u8>+Clone> Clone for LiteralCommand<SliceType> {
    #[inline(always)]
    fn clone(&self) -> LiteralCommand<SliceType>{
        LiteralCommand::<SliceType>{data:self.data.clone(), prob:self.prob.clone()}
    }
}
impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for LiteralCommand<SliceType> {
}

#[derive(Debug)]
pub struct RandLiteralCommand<SliceType:SliceWrapper<u8>> {
    pub data: SliceType,
}
impl<SliceType:SliceWrapper<u8>> SliceWrapper<u8> for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn slice(&self) -> &[u8] {
        self.data.slice()
    }
}
impl<SliceType:SliceWrapper<u8>+SliceWrapperMut<u8>> SliceWrapperMut<u8> for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn slice_mut(&mut self) -> &mut [u8] {
        self.data.slice_mut()
    }
}

impl<SliceType:SliceWrapper<u8>+Default> Nop<RandLiteralCommand<SliceType>> for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn nop() -> Self {
        RandLiteralCommand {
            data: SliceType::default(),
        }
    }
}
impl<SliceType:SliceWrapper<u8>+Clone> Clone for RandLiteralCommand<SliceType> {
    #[inline(always)]
    fn clone(&self) -> RandLiteralCommand<SliceType>{
        RandLiteralCommand::<SliceType>{data:self.data.clone()}
    }
}
impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for RandLiteralCommand<SliceType> {
}

#[derive(Debug)]
pub enum Command<SliceType:SliceWrapper<u8> > {
    Copy(CopyCommand),
    Dict(DictCommand),
    Literal(LiteralCommand<SliceType>),
    RandLiteral(RandLiteralCommand<SliceType>),
    BlockSwitchCommand(BlockSwitch),
    BlockSwitchLiteral(LiteralBlockSwitch),
    BlockSwitchDistance(BlockSwitch),
    PredictionMode(PredictionModeContextMap<SliceType>),
}
impl<SliceType:SliceWrapper<u8>+Default> Command<SliceType> {
    pub fn free_array<F>(&mut self, apply_func: &mut F) where F: FnMut(SliceType) {
       match self {
          &mut Command::Literal(ref mut lit) => {
             apply_func(core::mem::replace(&mut lit.data, SliceType::default()))
          },
          &mut Command::RandLiteral(ref mut lit) => {
             apply_func(core::mem::replace(&mut lit.data, SliceType::default()))
          },
          &mut Command::PredictionMode(ref mut pm) => {
             apply_func(core::mem::replace(&mut pm.literal_context_map, SliceType::default()));
             apply_func(core::mem::replace(&mut pm.distance_context_map, SliceType::default()));
          },
          _ => {},
       }
    }
}

impl<SliceType:SliceWrapper<u8>> Default for Command<SliceType> {
    #[inline(always)]
    fn default() -> Self {
        Command::<SliceType>::nop()
    }
}

impl<SliceType:SliceWrapper<u8>> Nop<Command<SliceType>> for Command<SliceType> {
    #[inline(always)]
    fn nop() -> Command<SliceType> {
        Command::Copy(CopyCommand::nop())
    }
}

impl<SliceType:SliceWrapper<u8>+Clone> Clone for Command<SliceType> {
    fn clone(&self) -> Command<SliceType>{
        match self {
            &Command::Copy(ref copy) => Command::Copy(copy.clone()),
            &Command::Dict(ref dict) => Command::Dict(dict.clone()),
            &Command::Literal(ref literal) => Command::Literal(literal.clone()),
            &Command::RandLiteral(ref literal) => Command::RandLiteral(literal.clone()),
            &Command::BlockSwitchCommand(ref switch) => Command::BlockSwitchCommand(switch.clone()),
            &Command::BlockSwitchLiteral(ref switch) => Command::BlockSwitchLiteral(switch.clone()),
            &Command::BlockSwitchDistance(ref switch) => Command::BlockSwitchDistance(switch.clone()),
            &Command::PredictionMode(ref pm) => Command::PredictionMode(pm.clone()),
        }
    }
}

impl<SliceType:SliceWrapper<u8>+Clone+Copy> Copy for Command<SliceType> {
}

pub fn free_cmd<SliceTypeAllocator:Allocator<u8>> (xself: &mut Command<SliceTypeAllocator::AllocatedMemory>, m8: &mut SliceTypeAllocator) {
       match *xself {
          Command::Literal(ref mut lit) => {
             m8.free_cell(core::mem::replace(&mut lit.data, SliceTypeAllocator::AllocatedMemory::default()))
          },
          Command::RandLiteral(ref mut lit) => {
             m8.free_cell(core::mem::replace(&mut lit.data, SliceTypeAllocator::AllocatedMemory::default()))
          },
          Command::PredictionMode(ref mut pm) => {
             m8.free_cell(core::mem::replace(&mut pm.literal_context_map, SliceTypeAllocator::AllocatedMemory::default()));
             m8.free_cell(core::mem::replace(&mut pm.distance_context_map, SliceTypeAllocator::AllocatedMemory::default()));
          },
          Command::Dict(_) |
          Command::Copy(_) |
          Command::BlockSwitchCommand(_) |
          Command::BlockSwitchLiteral(_) |
          Command::BlockSwitchDistance(_) => {},
    }
}
<|endoftext|>


<commit_before>use crate::citaprotocol::pubsub_message_to_network_message;
use crate::config::NetConfig;
use bytes::BytesMut;
use crossbeam_channel;
use crossbeam_channel::{select, tick, unbounded};
use discovery::RawAddr;
use fnv::FnvHashMap;
use libproto::{Message as ProtoMessage, TryInto};
use log::{debug, error, trace, warn};
use p2p::{context::ServiceControl, multiaddr::ToMultiaddr, SessionId};
use rand::{thread_rng, Rng};
use std::{
    collections::HashMap,
    net::{SocketAddr, ToSocketAddrs},
    time::{Duration, Instant},
};

pub const DEFAULT_MAX_CONNECTS: usize = 4;
pub const DEFAULT_PORT: usize = 4000;
pub const CHECK_CONNECTED_NODES: Duration = Duration::from_secs(3);

pub type PeerKey = u64;

pub struct NodesManager {
    check_connected_nodes: crossbeam_channel::Receiver<Instant>,
    known_addrs: FnvHashMap<RawAddr, i32>,
    connected_addrs: HashMap<SessionId, RawAddr>,
    connected_peer_keys: HashMap<PeerKey, SessionId>,
    max_connects: usize,
    nodes_manager_client: NodesManagerClient,
    nodes_manager_service_receiver: crossbeam_channel::Receiver<NodesManagerMessage>,
    service_ctrl: Option<ServiceControl>,
    my_peer_key: PeerKey,
}

impl NodesManager {
    pub fn new(known_addrs: FnvHashMap<RawAddr, i32>) -> Self {
        let mut node_mgr = NodesManager::default();
        let num = thread_rng().gen::<u64>();
        node_mgr.known_addrs = known_addrs;
        node_mgr.my_peer_key = num;
        node_mgr
    }

    pub fn from_config(cfg: NetConfig) -> Self {
        let mut node_mgr = NodesManager::default();
        let max_connects = cfg.max_connects.unwrap_or(DEFAULT_MAX_CONNECTS);
        node_mgr.max_connects = max_connects;

        if let Some(known_addrs) = cfg.peers {
            for addr in known_addrs {
                if let (Some(ip), Some(port)) = (addr.ip, addr.port) {
                    let addr_str = format!("{}:{}", ip, port);
                    match addr_str.to_socket_addrs() {
                        Ok(mut result) => {
                            if let Some(socket_addr) = result.next() {
                                let raw_addr = RawAddr::from(socket_addr);
                                node_mgr.known_addrs.insert(raw_addr, 100);
                            } else {
                                error!("[NodeManager] Can't convert to socket address!");
                            }
                        }
                        Err(e) => {
                            error!(
                                "[NodeManager] Can't convert to socket address! error: {}",
                                e
                            );
                        }
                    }
                } else {
                    warn!("[NodeManager] ip(host) & port 'MUST' be set in peers.");
                }
            }
        } else {
            warn!("NodeManager] Does not set any peers in config file!");
        }

        node_mgr
    }

    pub fn run(&mut self) {
        loop {
            select! {
                recv(self.nodes_manager_service_receiver) -> msg => {
                    match msg {
                        Ok(data) => {
                            data.handle(self);
                        },
                        Err(err) => debug!("Error in {:?}", err),
                    }
                }
                recv(self.check_connected_nodes) -> _ => {
                    self.dial_nodes();
                }
            }
        }
    }

    pub fn client(&self) -> NodesManagerClient {
        self.nodes_manager_client.clone()
    }

    pub fn dial_nodes(&mut self) {
        debug!("=============================");
        for raw_addr in self.known_addrs.keys() {
            debug!("Node in known: {:?}", raw_addr.socket_addr());
        }
        debug!("-----------------------------");
        for raw_addr in self.connected_addrs.values() {
            debug!("Node in connected: {:?}", raw_addr.socket_addr());
        }
        debug!("=============================");

        if self.connected_addrs.len() < self.max_connects {
            for key in self.known_addrs.keys() {
                if !self.connected_addrs.values().any(|value| *value == *key) {
                    debug!("[dial_nodes] Connect to {:?}", key.socket_addr());

                    if let Some(ref mut ctrl) = self.service_ctrl {
                        match ctrl.dial(key.socket_addr().to_multiaddr().unwrap()) {
                            Ok(_) => {
                                debug!("[dial_nodes] Dail success");
                            }
                            Err(err) => {
                                warn!("[dial_nodes] Dail failed : {:?}", err);
                            }
                        }
                    }
                    break;
                }
            }
        }
    }

    pub fn set_service_task_sender(&mut self, ctrl: ServiceControl) {
        self.service_ctrl = Some(ctrl);
    }
}

impl Default for NodesManager {
    fn default() -> NodesManager {
        let (tx, rx) = unbounded();
        let ticker = tick(CHECK_CONNECTED_NODES);
        let client = NodesManagerClient { sender: tx };

        NodesManager {
            check_connected_nodes: ticker,
            known_addrs: FnvHashMap::default(),
            connected_addrs: HashMap::default(),
            connected_peer_keys: HashMap::default(),
            max_connects: DEFAULT_MAX_CONNECTS,
            nodes_manager_client: client,
            nodes_manager_service_receiver: rx,
            service_ctrl: None,
            my_peer_key: 0,
        }
    }
}

#[derive(Clone, Debug)]
pub struct NodesManagerClient {
    sender: crossbeam_channel::Sender<NodesManagerMessage>,
}

impl NodesManagerClient {
    pub fn new(sender: crossbeam_channel::Sender<NodesManagerMessage>) -> Self {
        NodesManagerClient { sender }
    }

    pub fn add_node(&self, req: AddNodeReq) {
        self.send_req(NodesManagerMessage::AddNodeReq(req));
    }

    pub fn del_node(&self, req: DelNodeReq) {
        self.send_req(NodesManagerMessage::DelNodeReq(req));
    }

    pub fn get_random_nodes(&self, req: GetRandomNodesReq) {
        self.send_req(NodesManagerMessage::GetRandomNodesReq(req));
    }

    pub fn add_connected_node(&self, req: AddConnectedNodeReq) {
        self.send_req(NodesManagerMessage::AddConnectedNodeReq(req));
    }

    pub fn del_connected_node(&self, req: DelConnectedNodeReq) {
        self.send_req(NodesManagerMessage::DelConnectedNodeReq(req));
    }

    pub fn broadcast(&self, req: BroadcastReq) {
        self.send_req(NodesManagerMessage::Broadcast(req));
    }

    pub fn send_message(&self, req: SingleTxReq) {
        self.send_req(NodesManagerMessage::SingleTxReq(req));
    }

    pub fn get_peer_count(&self, req: GetPeerCountReq) {
        self.send_req(NodesManagerMessage::GetPeerCount(req));
    }

    fn send_req(&self, req: NodesManagerMessage) {
        match self.sender.try_send(req) {
            Ok(_) => {
                debug!("Send message to node manager Success");
            }
            Err(err) => {
                warn!("Send message to node manager failed : {:?}", err);
            }
        }
    }
}

// Define messages for NodesManager
pub enum NodesManagerMessage {
    AddNodeReq(AddNodeReq),
    DelNodeReq(DelNodeReq),
    GetRandomNodesReq(GetRandomNodesReq),
    AddConnectedNodeReq(AddConnectedNodeReq),
    DelConnectedNodeReq(DelConnectedNodeReq),
    Broadcast(BroadcastReq),
    SingleTxReq(SingleTxReq),
    GetPeerCount(GetPeerCountReq),
}

impl NodesManagerMessage {
    pub fn handle(self, service: &mut NodesManager) {
        match self {
            NodesManagerMessage::AddNodeReq(req) => req.handle(service),
            NodesManagerMessage::DelNodeReq(req) => req.handle(service),
            NodesManagerMessage::GetRandomNodesReq(req) => req.handle(service),
            NodesManagerMessage::AddConnectedNodeReq(req) => req.handle(service),
            NodesManagerMessage::DelConnectedNodeReq(req) => req.handle(service),
            NodesManagerMessage::Broadcast(req) => req.handle(service),
            NodesManagerMessage::SingleTxReq(req) => req.handle(service),
            NodesManagerMessage::GetPeerCount(req) => req.handle(service),
        }
    }
}

#[derive(Default, Clone)]
pub struct InitMsg {
    chain_id: u64,
    peer_key: PeerKey,
}

impl Into<Vec<u8>> for InitMsg {
    fn into(self) -> Vec<u8> {
        let mut out = Vec::new();
        out.extend_from_slice(&self.chain_id.to_be_bytes());
        out.extend_from_slice(&self.peer_key.to_be_bytes());
        out
    }
}

#[derive(Default)]
pub struct InitMsgReq {
    session_id: SessionId,
    init_msg: InitMsg,
}

impl InitMsgReq {
    pub fn new(session_id: SessionId, chain_id: u64, peer_key: PeerKey) -> Self {
        let init_msg = InitMsg { chain_id, peer_key };
        InitMsgReq {
            session_id,
            init_msg,
        }
    }

    pub fn handle(self, _service: &mut NodesManager) {}
}

pub struct AddNodeReq {
    addr: SocketAddr,
}

impl AddNodeReq {
    pub fn new(addr: SocketAddr) -> Self {
        AddNodeReq { addr }
    }

    pub fn handle(self, service: &mut NodesManager) {
        service
            .known_addrs
            .entry(RawAddr::from(self.addr))
            .or_insert(100);
    }
}

pub struct DelNodeReq {
    addr: SocketAddr,
}

impl DelNodeReq {
    pub fn new(addr: SocketAddr) -> Self {
        DelNodeReq { addr }
    }

    pub fn handle(self, service: &mut NodesManager) {
        service.known_addrs.remove(&RawAddr::from(self.addr));
    }
}

pub struct GetRandomNodesReq {
    num: usize,
    return_channel: crossbeam_channel::Sender<Vec<SocketAddr>>,
}

impl GetRandomNodesReq {
    pub fn new(num: usize, return_channel: crossbeam_channel::Sender<Vec<SocketAddr>>) -> Self {
        GetRandomNodesReq {
            num,
            return_channel,
        }
    }

    pub fn handle(self, service: &mut NodesManager) {
        let addrs = service
            .known_addrs
            .keys()
            .take(self.num)
            .map(|addr| addr.socket_addr())
            .collect();

        match self.return_channel.try_send(addrs) {
            Ok(_) => {
                debug!("Get random n nodes and send them success");
            }
            Err(err) => {
                warn!("Get random n nodes, send them failed : {:?}", err);
            }
        }
    }
}

pub struct AddConnectedNodeReq {
    addr: SocketAddr,
    session_id: SessionId,
}

impl AddConnectedNodeReq {
    pub fn new(addr: SocketAddr, session_id: SessionId) -> Self {
        AddConnectedNodeReq { addr, session_id }
    }

    pub fn handle(self, service: &mut NodesManager) {
        // FIXME: If have reached to max_connects, disconnected this node.
        let peer_key = service.my_peer_key;
        service
            .connected_addrs
            .insert(self.session_id, RawAddr::from(self.addr));

        let send_key = "init".to_string();
        let init_msg = InitMsg {
            chain_id: 0,
            peer_key,
        };
        let msg_bytes: Vec<u8> = init_msg.into();

        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + send_key.len() + msg_bytes.len());
        pubsub_message_to_network_message(&mut buf, Some((send_key, msg_bytes)));
        if let Some(ref mut ctrl) = service.service_ctrl {
            //FIXME: handle the error!
            let _ = ctrl.send_message(Some(vec![self.session_id]), 1, buf.to_vec());
        }
    }
}

pub struct DelConnectedNodeReq {
    session_id: SessionId,
}

impl DelConnectedNodeReq {
    pub fn new(session_id: SessionId) -> Self {
        DelConnectedNodeReq { session_id }
    }

    pub fn handle(self, service: &mut NodesManager) {
        service.connected_addrs.remove(&self.session_id);
    }
}

#[derive(Debug)]
pub struct BroadcastReq {
    key: String,
    msg: ProtoMessage,
}

impl BroadcastReq {
    pub fn new(key: String, msg: ProtoMessage) -> Self {
        BroadcastReq { key, msg }
    }

    pub fn handle(self, service: &mut NodesManager) {
        trace!("Broadcast msg {:?}, from key {}", self.msg, self.key);
        let msg_bytes: Vec<u8> = self.msg.try_into().unwrap();

        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + self.key.len() + msg_bytes.len());
        pubsub_message_to_network_message(&mut buf, Some((self.key, msg_bytes)));
        if let Some(ref mut ctrl) = service.service_ctrl {
            let _ = ctrl.send_message(None, 1, buf.to_vec());
        }
    }
}

pub struct SingleTxReq {
    dst: SessionId,
    key: String,
    msg: ProtoMessage,
}

impl SingleTxReq {
    pub fn new(dst: SessionId, key: String, msg: ProtoMessage) -> Self {
        SingleTxReq { dst, key, msg }
    }

    pub fn handle(self, service: &mut NodesManager) {
        trace!(
            "Send msg {:?} to {}, from key {}",
            self.msg,
            self.dst,
            self.key
        );
        let msg_bytes: Vec<u8> = self.msg.try_into().unwrap();

        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + self.key.len() + msg_bytes.len());
        pubsub_message_to_network_message(&mut buf, Some((self.key, msg_bytes)));
        if let Some(ref mut ctrl) = service.service_ctrl {
            //FIXME: handle the error!
            let _ = ctrl.send_message(Some(vec![self.dst]), 1, buf.to_vec());
        }
    }
}

pub struct GetPeerCountReq {
    return_channel: crossbeam_channel::Sender<usize>,
}

impl GetPeerCountReq {
    pub fn new(return_channel: crossbeam_channel::Sender<usize>) -> Self {
        GetPeerCountReq { return_channel }
    }

    pub fn handle(self, service: &mut NodesManager) {
        let peer_count = service.connected_addrs.len();

        match self.return_channel.try_send(peer_count) {
            Ok(_) => {
                debug!("Get peer count and send it success");
            }
            Err(err) => {
                warn!(
                    "Get peer count {}, but send it failed : {:?}",
                    peer_count, err
                );
            }
        }
    }
}
<commit_msg>fix peer_key init error<commit_after>use crate::citaprotocol::pubsub_message_to_network_message;
use crate::config::NetConfig;
use bytes::BytesMut;
use crossbeam_channel;
use crossbeam_channel::{select, tick, unbounded};
use discovery::RawAddr;
use fnv::FnvHashMap;
use libproto::{Message as ProtoMessage, TryInto};
use log::{debug, error, trace, warn};
use p2p::{context::ServiceControl, multiaddr::ToMultiaddr, SessionId};
use rand::{thread_rng, Rng};
use std::{
    collections::HashMap,
    net::{SocketAddr, ToSocketAddrs},
    time::{Duration, Instant},
};

pub const DEFAULT_MAX_CONNECTS: usize = 4;
pub const DEFAULT_PORT: usize = 4000;
pub const CHECK_CONNECTED_NODES: Duration = Duration::from_secs(3);

pub type PeerKey = u64;

pub struct NodesManager {
    check_connected_nodes: crossbeam_channel::Receiver<Instant>,
    known_addrs: FnvHashMap<RawAddr, i32>,
    connected_addrs: HashMap<SessionId, RawAddr>,
    connected_peer_keys: HashMap<PeerKey, SessionId>,
    max_connects: usize,
    nodes_manager_client: NodesManagerClient,
    nodes_manager_service_receiver: crossbeam_channel::Receiver<NodesManagerMessage>,
    service_ctrl: Option<ServiceControl>,
    peer_key: PeerKey,
}

impl NodesManager {
    pub fn new(known_addrs: FnvHashMap<RawAddr, i32>) -> Self {
        let mut node_mgr = NodesManager::default();
        node_mgr.known_addrs = known_addrs;
        node_mgr
    }

    pub fn from_config(cfg: NetConfig) -> Self {
        let mut node_mgr = NodesManager::default();
        let max_connects = cfg.max_connects.unwrap_or(DEFAULT_MAX_CONNECTS);
        node_mgr.max_connects = max_connects;

        if let Some(known_addrs) = cfg.peers {
            for addr in known_addrs {
                if let (Some(ip), Some(port)) = (addr.ip, addr.port) {
                    let addr_str = format!("{}:{}", ip, port);
                    match addr_str.to_socket_addrs() {
                        Ok(mut result) => {
                            if let Some(socket_addr) = result.next() {
                                let raw_addr = RawAddr::from(socket_addr);
                                node_mgr.known_addrs.insert(raw_addr, 100);
                            } else {
                                error!("[NodeManager] Can't convert to socket address!");
                            }
                        }
                        Err(e) => {
                            error!(
                                "[NodeManager] Can't convert to socket address! error: {}",
                                e
                            );
                        }
                    }
                } else {
                    warn!("[NodeManager] ip(host) & port 'MUST' be set in peers.");
                }
            }
        } else {
            warn!("NodeManager] Does not set any peers in config file!");
        }

        node_mgr
    }

    pub fn run(&mut self) {
        loop {
            select! {
                recv(self.nodes_manager_service_receiver) -> msg => {
                    match msg {
                        Ok(data) => {
                            data.handle(self);
                        },
                        Err(err) => debug!("Error in {:?}", err),
                    }
                }
                recv(self.check_connected_nodes) -> _ => {
                    self.dial_nodes();
                }
            }
        }
    }

    pub fn client(&self) -> NodesManagerClient {
        self.nodes_manager_client.clone()
    }

    pub fn dial_nodes(&mut self) {
        debug!("=============================");
        for raw_addr in self.known_addrs.keys() {
            debug!("Node in known: {:?}", raw_addr.socket_addr());
        }
        debug!("-----------------------------");
        for raw_addr in self.connected_addrs.values() {
            debug!("Node in connected: {:?}", raw_addr.socket_addr());
        }
        debug!("=============================");

        if self.connected_addrs.len() < self.max_connects {
            for key in self.known_addrs.keys() {
                if !self.connected_addrs.values().any(|value| *value == *key) {
                    debug!("[dial_nodes] Connect to {:?}", key.socket_addr());

                    if let Some(ref mut ctrl) = self.service_ctrl {
                        match ctrl.dial(key.socket_addr().to_multiaddr().unwrap()) {
                            Ok(_) => {
                                debug!("[dial_nodes] Dail success");
                            }
                            Err(err) => {
                                warn!("[dial_nodes] Dail failed : {:?}", err);
                            }
                        }
                    }
                    break;
                }
            }
        }
    }

    pub fn set_service_task_sender(&mut self, ctrl: ServiceControl) {
        self.service_ctrl = Some(ctrl);
    }
}

impl Default for NodesManager {
    fn default() -> NodesManager {
        let (tx, rx) = unbounded();
        let ticker = tick(CHECK_CONNECTED_NODES);
        let client = NodesManagerClient { sender: tx };
        let peer_key = thread_rng().gen::<u64>();

        NodesManager {
            check_connected_nodes: ticker,
            known_addrs: FnvHashMap::default(),
            connected_addrs: HashMap::default(),
            connected_peer_keys: HashMap::default(),
            max_connects: DEFAULT_MAX_CONNECTS,
            nodes_manager_client: client,
            nodes_manager_service_receiver: rx,
            service_ctrl: None,
            peer_key,
        }
    }
}

#[derive(Clone, Debug)]
pub struct NodesManagerClient {
    sender: crossbeam_channel::Sender<NodesManagerMessage>,
}

impl NodesManagerClient {
    pub fn new(sender: crossbeam_channel::Sender<NodesManagerMessage>) -> Self {
        NodesManagerClient { sender }
    }

    pub fn add_node(&self, req: AddNodeReq) {
        self.send_req(NodesManagerMessage::AddNodeReq(req));
    }

    pub fn del_node(&self, req: DelNodeReq) {
        self.send_req(NodesManagerMessage::DelNodeReq(req));
    }

    pub fn get_random_nodes(&self, req: GetRandomNodesReq) {
        self.send_req(NodesManagerMessage::GetRandomNodesReq(req));
    }

    pub fn add_connected_node(&self, req: AddConnectedNodeReq) {
        self.send_req(NodesManagerMessage::AddConnectedNodeReq(req));
    }

    pub fn del_connected_node(&self, req: DelConnectedNodeReq) {
        self.send_req(NodesManagerMessage::DelConnectedNodeReq(req));
    }

    pub fn broadcast(&self, req: BroadcastReq) {
        self.send_req(NodesManagerMessage::Broadcast(req));
    }

    pub fn send_message(&self, req: SingleTxReq) {
        self.send_req(NodesManagerMessage::SingleTxReq(req));
    }

    pub fn get_peer_count(&self, req: GetPeerCountReq) {
        self.send_req(NodesManagerMessage::GetPeerCount(req));
    }

    fn send_req(&self, req: NodesManagerMessage) {
        match self.sender.try_send(req) {
            Ok(_) => {
                debug!("Send message to node manager Success");
            }
            Err(err) => {
                warn!("Send message to node manager failed : {:?}", err);
            }
        }
    }
}

// Define messages for NodesManager
pub enum NodesManagerMessage {
    AddNodeReq(AddNodeReq),
    DelNodeReq(DelNodeReq),
    GetRandomNodesReq(GetRandomNodesReq),
    AddConnectedNodeReq(AddConnectedNodeReq),
    DelConnectedNodeReq(DelConnectedNodeReq),
    Broadcast(BroadcastReq),
    SingleTxReq(SingleTxReq),
    GetPeerCount(GetPeerCountReq),
}

impl NodesManagerMessage {
    pub fn handle(self, service: &mut NodesManager) {
        match self {
            NodesManagerMessage::AddNodeReq(req) => req.handle(service),
            NodesManagerMessage::DelNodeReq(req) => req.handle(service),
            NodesManagerMessage::GetRandomNodesReq(req) => req.handle(service),
            NodesManagerMessage::AddConnectedNodeReq(req) => req.handle(service),
            NodesManagerMessage::DelConnectedNodeReq(req) => req.handle(service),
            NodesManagerMessage::Broadcast(req) => req.handle(service),
            NodesManagerMessage::SingleTxReq(req) => req.handle(service),
            NodesManagerMessage::GetPeerCount(req) => req.handle(service),
        }
    }
}

#[derive(Default, Clone)]
pub struct InitMsg {
    chain_id: u64,
    peer_key: PeerKey,
}

impl Into<Vec<u8>> for InitMsg {
    fn into(self) -> Vec<u8> {
        let mut out = Vec::new();
        out.extend_from_slice(&self.chain_id.to_be_bytes());
        out.extend_from_slice(&self.peer_key.to_be_bytes());
        out
    }
}

#[derive(Default)]
pub struct InitMsgReq {
    session_id: SessionId,
    init_msg: InitMsg,
}

impl InitMsgReq {
    pub fn new(session_id: SessionId, chain_id: u64, peer_key: PeerKey) -> Self {
        let init_msg = InitMsg { chain_id, peer_key };
        InitMsgReq {
            session_id,
            init_msg,
        }
    }

    pub fn handle(self, _service: &mut NodesManager) {}
}

pub struct AddNodeReq {
    addr: SocketAddr,
}

impl AddNodeReq {
    pub fn new(addr: SocketAddr) -> Self {
        AddNodeReq { addr }
    }

    pub fn handle(self, service: &mut NodesManager) {
        service
            .known_addrs
            .entry(RawAddr::from(self.addr))
            .or_insert(100);
    }
}

pub struct DelNodeReq {
    addr: SocketAddr,
}

impl DelNodeReq {
    pub fn new(addr: SocketAddr) -> Self {
        DelNodeReq { addr }
    }

    pub fn handle(self, service: &mut NodesManager) {
        service.known_addrs.remove(&RawAddr::from(self.addr));
    }
}

pub struct GetRandomNodesReq {
    num: usize,
    return_channel: crossbeam_channel::Sender<Vec<SocketAddr>>,
}

impl GetRandomNodesReq {
    pub fn new(num: usize, return_channel: crossbeam_channel::Sender<Vec<SocketAddr>>) -> Self {
        GetRandomNodesReq {
            num,
            return_channel,
        }
    }

    pub fn handle(self, service: &mut NodesManager) {
        let addrs = service
            .known_addrs
            .keys()
            .take(self.num)
            .map(|addr| addr.socket_addr())
            .collect();

        match self.return_channel.try_send(addrs) {
            Ok(_) => {
                debug!("Get random n nodes and send them success");
            }
            Err(err) => {
                warn!("Get random n nodes, send them failed : {:?}", err);
            }
        }
    }
}

pub struct AddConnectedNodeReq {
    addr: SocketAddr,
    session_id: SessionId,
}

impl AddConnectedNodeReq {
    pub fn new(addr: SocketAddr, session_id: SessionId) -> Self {
        AddConnectedNodeReq { addr, session_id }
    }

    pub fn handle(self, service: &mut NodesManager) {
        // FIXME: If have reached to max_connects, disconnected this node.
        let peer_key = service.peer_key;
        service
            .connected_addrs
            .insert(self.session_id, RawAddr::from(self.addr));

        let send_key = "init".to_string();
        let init_msg = InitMsg {
            chain_id: 0,
            peer_key,
        };
        let msg_bytes: Vec<u8> = init_msg.into();

        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + send_key.len() + msg_bytes.len());
        pubsub_message_to_network_message(&mut buf, Some((send_key, msg_bytes)));
        if let Some(ref mut ctrl) = service.service_ctrl {
            //FIXME: handle the error!
            let _ = ctrl.send_message(Some(vec![self.session_id]), 1, buf.to_vec());
        }
    }
}

pub struct DelConnectedNodeReq {
    session_id: SessionId,
}

impl DelConnectedNodeReq {
    pub fn new(session_id: SessionId) -> Self {
        DelConnectedNodeReq { session_id }
    }

    pub fn handle(self, service: &mut NodesManager) {
        service.connected_addrs.remove(&self.session_id);
    }
}

#[derive(Debug)]
pub struct BroadcastReq {
    key: String,
    msg: ProtoMessage,
}

impl BroadcastReq {
    pub fn new(key: String, msg: ProtoMessage) -> Self {
        BroadcastReq { key, msg }
    }

    pub fn handle(self, service: &mut NodesManager) {
        trace!("Broadcast msg {:?}, from key {}", self.msg, self.key);
        let msg_bytes: Vec<u8> = self.msg.try_into().unwrap();

        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + self.key.len() + msg_bytes.len());
        pubsub_message_to_network_message(&mut buf, Some((self.key, msg_bytes)));
        if let Some(ref mut ctrl) = service.service_ctrl {
            let _ = ctrl.send_message(None, 1, buf.to_vec());
        }
    }
}

pub struct SingleTxReq {
    dst: SessionId,
    key: String,
    msg: ProtoMessage,
}

impl SingleTxReq {
    pub fn new(dst: SessionId, key: String, msg: ProtoMessage) -> Self {
        SingleTxReq { dst, key, msg }
    }

    pub fn handle(self, service: &mut NodesManager) {
        trace!(
            "Send msg {:?} to {}, from key {}",
            self.msg,
            self.dst,
            self.key
        );
        let msg_bytes: Vec<u8> = self.msg.try_into().unwrap();

        let mut buf = BytesMut::with_capacity(4 + 4 + 1 + self.key.len() + msg_bytes.len());
        pubsub_message_to_network_message(&mut buf, Some((self.key, msg_bytes)));
        if let Some(ref mut ctrl) = service.service_ctrl {
            //FIXME: handle the error!
            let _ = ctrl.send_message(Some(vec![self.dst]), 1, buf.to_vec());
        }
    }
}

pub struct GetPeerCountReq {
    return_channel: crossbeam_channel::Sender<usize>,
}

impl GetPeerCountReq {
    pub fn new(return_channel: crossbeam_channel::Sender<usize>) -> Self {
        GetPeerCountReq { return_channel }
    }

    pub fn handle(self, service: &mut NodesManager) {
        let peer_count = service.connected_addrs.len();

        match self.return_channel.try_send(peer_count) {
            Ok(_) => {
                debug!("Get peer count and send it success");
            }
            Err(err) => {
                warn!(
                    "Get peer count {}, but send it failed : {:?}",
                    peer_count, err
                );
            }
        }
    }
}
<|endoftext|>


<commit_before>use connection::Connection;
use libproto::blockchain::{Block, Status};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::{Message, OperateType, SyncRequest, SyncResponse};
use rand::{thread_rng, Rng, ThreadRng};
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::convert::{Into, TryFrom, TryInto};
use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use std::u8;
use Source;

const SYNC_STEP: u64 = 20;
const SYNC_TIME_OUT: u64 = 9;

/// Get messages and determine if need to synchronize or broadcast the current node status
pub struct Synchronizer {
    tx_pub: mpsc::Sender<(String, Vec<u8>)>,
    con: Arc<Connection>,
    current_status: Status,
    global_status: Status,
    sync_end_height: u64, //current_status <= sync_end_status
    is_synchronizing: bool,
    latest_status_lists: BTreeMap<u64, VecDeque<u32>>,
    block_lists: BTreeMap<u64, Block>,
    rand: ThreadRng,
    // Timer for each height processing
    remote_sync_time_out: Instant,
    /// local sync error
    local_sync_count: u8,
}

unsafe impl Sync for Synchronizer {}
unsafe impl Send for Synchronizer {}

impl Synchronizer {
    pub fn new(tx_pub: mpsc::Sender<(String, Vec<u8>)>, con: Arc<Connection>) -> Self {
        Synchronizer {
            tx_pub: tx_pub,
            con: con,
            current_status: Status::new(),
            global_status: Status::new(),
            latest_status_lists: BTreeMap::new(),
            sync_end_height: 0,
            is_synchronizing: false,
            block_lists: BTreeMap::new(),
            rand: thread_rng(),
            remote_sync_time_out: (Instant::now() - Duration::from_secs(SYNC_TIME_OUT)),
            local_sync_count: 0,
        }
    }

    /// After receiving the `Chain >> Status`, it is processed as follows:
    /// 1. The chain height suddenly becomes lower than the original,
    ///    which means that the library is deleted, that is,
    ///    the synchronization is restarted from the received height.
    /// 2. The height of the chain is greater than or equal to the original height,
    ///    less than or equal to the height that the network has synchronized
    ///        - It is equal to the original height more than 2 times, indicating that
    ///          the data in the chain or executor is lost, and the block information is
    ///          sent again from the buffer. If no buffer exists, the data is requested again from other nodes.
    /// 3. The height is greater than or equal to the global height, indicating that the synchronization
    ///     has been completed and the synchronization status is exited.
    /// 4. The height is less than the global height, indicating that synchronization needs to be continued
    /// 5. Other unknown state
    pub fn update_current_status(&mut self, latest_status: Status) {
        debug!(
            "sync: update_current_status: current height = {}, \
             before height = {}, \
             sync_end_height = {}",
            latest_status.get_height(),
            self.current_status.get_height(),
            self.sync_end_height
        );
        let old_height = self.current_status.get_height();
        let new_height = latest_status.get_height();

        if new_height == old_height {
            if self.local_sync_count < u8::MAX {
                // Chain height does not increase
                self.local_sync_count += 1;
            }
        } else {
            self.local_sync_count = 0;
            self.remote_sync_time_out = Instant::now();
        }

        self.latest_status_lists = self
            .latest_status_lists
            .split_off(&(latest_status.get_height() + 1));
        self.current_status = latest_status;
        self.broadcast_status();
        self.prune_block_list_cache(new_height + 1);

        info!(
            "current: {}, sync_end: {}, global: {}, sync: {}",
            new_height,
            self.sync_end_height,
            self.global_status.get_height(),
            self.is_synchronizing
        );

        if new_height < old_height {
            // Chain error, may be a problem with the database, such as the database was deleted
            let start_height = new_height + 1;

            if self.block_lists.contains_key(&start_height) && !self.block_lists.is_empty() {
                self.submit_blocks();
            } else {
                self.start_sync_req(start_height);
            }
        } else if new_height < self.sync_end_height {
            // In synchronization, or loss of sync data, need to resend
            debug!(
                "Syncing: update_current_status: height = {}, block_lists len = {}",
                new_height,
                self.block_lists.len()
            );

            if !self.block_lists.is_empty() && new_height < self.sync_end_height {
                if self.local_sync_count >= 3 {
                    // Chain height does not increase, loss data or data is invalid,
                    // send cache to executor and chain, and clear cache
                    self.local_sync_count = 0;
                    self.block_lists.clear();
                    self.start_sync_req(new_height + 1);
                    info!("More than 3 times, clear the cache");
                }
            }

            self.is_synchronizing = true;
        } else if new_height >= self.global_status.get_height() {
            if self.is_synchronizing {
                self.is_synchronizing = false;
                self.sync_end_height = 0;
            }
        } else if new_height < self.global_status.get_height() {
            // If the block height is equal to the maximum height that has already been synchronized,
            // perform the synchronization operation first to see if it is the latest in the chain
            if self.is_synchronizing {
                self.start_sync_req(new_height + 1);
            }
        } else {
            info!("...Can't reach this");
        }
    }

    /// 1. Global height is less than current height + 1, no action
    /// 2. Global height is equal to current height + 1
    ///     - The global height continues to increase, and if the current state is not synchronized,
    ///       the synchronization request is initiated immediately.
    ///     - If the global height is no longer growing, after the predetermined time has elapsed,
    ///       the synchronization request is also initiated.
    /// 3. Global height is greater than current height + 1, Timeout or not in sync, initiate synchronization
    pub fn update_global_status(&mut self, status: &Status, origin: u32) {
        debug!(
            "sync: update_global_status: current height = {}, from node = {}, height = {}",
            self.current_status.get_height(),
            origin,
            status.get_height()
        );
        let current_height = self.current_status.get_height();
        if self.global_status.get_height() < status.get_height() {
            self.global_status = status.clone();
        }

        if status.get_height() < current_height + 1 {
            // The current node is the latest height and does not need to be synchronized
        } else if status.get_height() == current_height + 1 {
            // A node on the chain blocks out, synchronizing the latest block
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                && !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        } else {
            // The node is far behind the data on the chain and initiates a synchronization request
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                || !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        }
    }

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

    pub fn process_sync(&mut self, mut blocks: SyncResponse) {
        let blocks = blocks.take_blocks();
        debug!("sync: process_sync: blocks len = {}", blocks.len());

        let mut heights = vec![];
        for block in blocks.into_iter() {
            heights.push(block.get_header().get_height());
            self.block_lists
                .insert(block.get_header().get_height(), block);
        }

        debug!("sync: process_sync: heights = {:?}", heights);
        self.submit_blocks();
    }

    pub fn receive(&mut self, _from: Source, payload: (String, Vec<u8>)) {
        let (key, body) = payload;
        let mut msg = Message::try_from(&body).unwrap();
        let origin = msg.get_origin();
        match RoutingKey::from(&key) {
            routing_key!(Chain >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_current_status(status);
                };
            }
            routing_key!(Synchronizer >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_global_status(&status, origin);
                };
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                if let Some(blocks) = msg.take_sync_response() {
                    self.process_sync(blocks);
                };
            }
            _ => {
                error!("receive: unexpected data key = {:?}", key);
            }
        }
    }

    // Initiate a sync request
    fn start_sync_req(&mut self, start_height: u64) {
        debug!(
            "sync: start_sync_req: start_height = {}, current height = {}",
            start_height,
            self.current_status.get_height()
        );
        let mut origin = 0;
        let mut end_height = start_height;
        let mut is_send = false;
        let current_height = self.current_status.get_height();

        if let Some((height, origins)) = self
            .latest_status_lists
            .iter()
            .rfind(|&(_, origins)| origins.len() > 0)
        {
            debug!(
                "sync: start_sync_req: height = {}, origins = {:?}",
                height, origins
            );
            if let Some(origins) = self.latest_status_lists.get(height) {
                if *height > current_height {
                    origin = origins[self.rand.gen_range(0, origins.len())];
                    end_height = if *height + 1 > current_height + SYNC_STEP {
                        current_height + SYNC_STEP
                    } else {
                        *height + 1
                    };
                    is_send = true;
                }
            }
        }

        if is_send {
            self.sync_strategy(start_height, end_height, origin);
        }
    }

    fn sync_strategy(&self, start_height: u64, end_height: u64, origin: u32) {
        //current height = 155,start_height = 156, end height = 160, to origin = 1
        debug!(
            "sync: sync_strategy: current height = {}, \
             start_height = {}, \
             end height = {}, \
             to origin = {}",
            self.current_status.get_height(),
            start_height,
            end_height,
            origin
        );
        if start_height >= self.current_status.get_height() && start_height <= end_height {
            let mut start_height = start_height;
            let mut step_sum = SYNC_STEP;
            let mut heights = vec![];

            while start_height <= end_height {
                if step_sum == 0 {
                    step_sum = SYNC_STEP;
                    self.send_sync_req(heights, origin);
                    heights = vec![];
                }
                heights.push(start_height);

                step_sum -= 1;
                start_height += 1;
            }
            self.send_sync_req(heights, origin);
        }
    }

    fn send_sync_req(&self, heights: Vec<u64>, origin: u32) {
        if !heights.is_empty() {
            debug!(
                "sync: send_sync_req:current height = {}, \
                 heights = {:?}, \
                 origin {:?}, \
                 chain.sync: OperateType {:?}",
                self.current_status.get_height(),
                heights,
                origin,
                OperateType::Single
            );
            let mut sync_req = SyncRequest::new();
            sync_req.set_heights(heights);
            let msg = Message::init(OperateType::Single, origin, sync_req.into());
            self.con
                .broadcast(routing_key!(Synchronizer >> SyncRequest).into(), msg);
        }
    }

    fn broadcast_status(&mut self) {
        debug!(
            "sync: broadcast status {:?}, {:?} to other nodes",
            self.current_status.get_height(),
            self.current_status.get_hash()
        );
        let msg: Message = self.current_status.clone().into();
        self.con
            .broadcast(routing_key!(Synchronizer >> Status).into(), msg);
    }

    // Submit synchronization information
    fn submit_blocks(&mut self) {
        let mut height = self.current_status.get_height() + 1;
        debug!(
            "sync: submit_blocks:submit_height = {},\
             current height = {},\
             sync_end_height = {},\
             block_lists = {}",
            height,
            self.current_status.get_height(),
            self.sync_end_height,
            self.block_lists.len()
        );
        let mut blocks = vec![];
        let end_height = height + SYNC_STEP;

        loop {
            if height <= end_height {
                if let Some(block) = self.block_lists.get(&height) {
                    blocks.push(block.to_owned());
                } else {
                    break;
                }
            } else {
                break;
            }
            height += 1;
        }

        match blocks.last() {
            Some(block) => {
                if let Some(header) = block.header.as_ref() {
                    let height = header.get_height() - 1;

                    if height > self.sync_end_height {
                        self.sync_end_height = height;
                    }
                }
            }
            None => {}
        }

        if self.block_lists.contains_key(&::std::u64::MAX) {
            blocks.push(self.block_lists.remove(&::std::u64::MAX).unwrap());
        }

        self.pub_blocks(blocks);
        self.is_synchronizing = true;
        self.remote_sync_time_out = Instant::now();
    }

    fn pub_blocks(&mut self, blocks: Vec<Block>) {
        if !blocks.is_empty() {
            debug!(
                "sync: pub_blocks: current height = {}, \
                 sync_end_height = {}, \
                 len = {}, ",
                self.current_status.get_height(),
                self.sync_end_height,
                blocks.len()
            );
            let mut sync_res = SyncResponse::new();
            sync_res.set_blocks(blocks.into());
            let msg: Message = sync_res.into();
            self.tx_pub.send((
                routing_key!(Net >> SyncResponse).into(),
                msg.try_into().unwrap(),
            ));
        }
    }

    fn add_latest_sync_lists(&mut self, height: u64, origin: u32) {
        debug!(
            "sync: add_sync_lists: current height = {}, \
             from node = {}, \
             height = {}",
            self.current_status.get_height(),
            origin,
            height
        );
        if self
            .latest_status_lists
            .entry(height)
            .or_insert_with(VecDeque::new)
            .iter()
            .fold(HashSet::new(), |mut set, item| {
                set.insert(item);
                set
            })
            .insert(&origin)
        {
            self.latest_status_lists
                .entry(height)
                .or_insert_with(VecDeque::new)
                .push_back(origin);
        }
    }

    /// Prune block on btreemap
    fn prune_block_list_cache(&mut self, height: u64) {
        self.block_lists = self.block_lists.split_off(&height);
    }
}
<commit_msg>sync finish, clear block list<commit_after>use connection::Connection;
use libproto::blockchain::{Block, Status};
use libproto::router::{MsgType, RoutingKey, SubModules};
use libproto::{Message, OperateType, SyncRequest, SyncResponse};
use rand::{thread_rng, Rng, ThreadRng};
use std::collections::{BTreeMap, HashSet, VecDeque};
use std::convert::{Into, TryFrom, TryInto};
use std::sync::{mpsc, Arc};
use std::time::{Duration, Instant};
use std::u8;
use Source;

const SYNC_STEP: u64 = 20;
const SYNC_TIME_OUT: u64 = 9;

/// Get messages and determine if need to synchronize or broadcast the current node status
pub struct Synchronizer {
    tx_pub: mpsc::Sender<(String, Vec<u8>)>,
    con: Arc<Connection>,
    current_status: Status,
    global_status: Status,
    sync_end_height: u64, //current_status <= sync_end_status
    is_synchronizing: bool,
    latest_status_lists: BTreeMap<u64, VecDeque<u32>>,
    block_lists: BTreeMap<u64, Block>,
    rand: ThreadRng,
    // Timer for each height processing
    remote_sync_time_out: Instant,
    /// local sync error
    local_sync_count: u8,
}

unsafe impl Sync for Synchronizer {}
unsafe impl Send for Synchronizer {}

impl Synchronizer {
    pub fn new(tx_pub: mpsc::Sender<(String, Vec<u8>)>, con: Arc<Connection>) -> Self {
        Synchronizer {
            tx_pub: tx_pub,
            con: con,
            current_status: Status::new(),
            global_status: Status::new(),
            latest_status_lists: BTreeMap::new(),
            sync_end_height: 0,
            is_synchronizing: false,
            block_lists: BTreeMap::new(),
            rand: thread_rng(),
            remote_sync_time_out: (Instant::now() - Duration::from_secs(SYNC_TIME_OUT)),
            local_sync_count: 0,
        }
    }

    /// After receiving the `Chain >> Status`, it is processed as follows:
    /// 1. The chain height suddenly becomes lower than the original,
    ///    which means that the library is deleted, that is,
    ///    the synchronization is restarted from the received height.
    /// 2. The height of the chain is greater than or equal to the original height,
    ///    less than or equal to the height that the network has synchronized
    ///        - It is equal to the original height more than 2 times, indicating that
    ///          the data in the chain or executor is lost, and the block information is
    ///          sent again from the buffer. If no buffer exists, the data is requested again from other nodes.
    /// 3. The height is greater than or equal to the global height, indicating that the synchronization
    ///     has been completed and the synchronization status is exited.
    /// 4. The height is less than the global height, indicating that synchronization needs to be continued
    /// 5. Other unknown state
    pub fn update_current_status(&mut self, latest_status: Status) {
        debug!(
            "sync: update_current_status: current height = {}, \
             before height = {}, \
             sync_end_height = {}",
            latest_status.get_height(),
            self.current_status.get_height(),
            self.sync_end_height
        );
        let old_height = self.current_status.get_height();
        let new_height = latest_status.get_height();

        if new_height == old_height {
            if self.local_sync_count < u8::MAX {
                // Chain height does not increase
                self.local_sync_count += 1;
            }
        } else {
            self.local_sync_count = 0;
            self.remote_sync_time_out = Instant::now();
        }

        self.latest_status_lists = self
            .latest_status_lists
            .split_off(&(latest_status.get_height() + 1));
        self.current_status = latest_status;
        self.broadcast_status();
        self.prune_block_list_cache(new_height + 1);

        info!(
            "current: {}, sync_end: {}, global: {}, sync: {}",
            new_height,
            self.sync_end_height,
            self.global_status.get_height(),
            self.is_synchronizing
        );

        if new_height < old_height {
            // Chain error, may be a problem with the database, such as the database was deleted
            let start_height = new_height + 1;

            if self.block_lists.contains_key(&start_height) && !self.block_lists.is_empty() {
                self.submit_blocks();
            } else {
                self.start_sync_req(start_height);
            }
        } else if new_height < self.sync_end_height {
            // In synchronization, or loss of sync data, need to resend
            debug!(
                "Syncing: update_current_status: height = {}, block_lists len = {}",
                new_height,
                self.block_lists.len()
            );

            if !self.block_lists.is_empty() && new_height < self.sync_end_height {
                if self.local_sync_count >= 3 {
                    // Chain height does not increase, loss data or data is invalid,
                    // send cache to executor and chain, and clear cache
                    self.local_sync_count = 0;
                    self.block_lists.clear();
                    self.start_sync_req(new_height + 1);
                    info!("More than 3 times, clear the cache");
                }
            }

            self.is_synchronizing = true;
        } else if new_height >= self.global_status.get_height() {
            if self.is_synchronizing {
                self.is_synchronizing = false;
                self.sync_end_height = 0;
                self.block_lists.clear();
            }
        } else if new_height < self.global_status.get_height() {
            // If the block height is equal to the maximum height that has already been synchronized,
            // perform the synchronization operation first to see if it is the latest in the chain
            if self.is_synchronizing {
                self.start_sync_req(new_height + 1);
            }
        } else {
            info!("...Can't reach this");
        }
    }

    /// 1. Global height is less than current height + 1, no action
    /// 2. Global height is equal to current height + 1
    ///     - Start syncing when it is not in sync and timeout
    /// 3. Global height is greater than current height + 1, Timeout or not in sync, initiate synchronization
    pub fn update_global_status(&mut self, status: &Status, origin: u32) {
        debug!(
            "sync: update_global_status: current height = {}, from node = {}, height = {}",
            self.current_status.get_height(),
            origin,
            status.get_height()
        );
        let current_height = self.current_status.get_height();
        if self.global_status.get_height() < status.get_height() {
            self.global_status = status.clone();
        }

        if status.get_height() < current_height + 1 {
            // The current node is the latest height and does not need to be synchronized
        } else if status.get_height() == current_height + 1 {
            // A node on the chain blocks out, synchronizing the latest block
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                && !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        } else {
            // The node is far behind the data on the chain and initiates a synchronization request
            self.add_latest_sync_lists(status.get_height(), origin);

            if self.remote_sync_time_out.elapsed().as_secs() > SYNC_TIME_OUT
                || !self.is_synchronizing
            {
                self.start_sync_req(current_height + 1);
            }
        }
    }

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

    pub fn process_sync(&mut self, mut blocks: SyncResponse) {
        let blocks = blocks.take_blocks();
        debug!("sync: process_sync: blocks len = {}", blocks.len());

        let mut heights = vec![];
        for block in blocks.into_iter() {
            heights.push(block.get_header().get_height());
            self.block_lists
                .insert(block.get_header().get_height(), block);
        }

        debug!("sync: process_sync: heights = {:?}", heights);
        self.submit_blocks();
    }

    pub fn receive(&mut self, _from: Source, payload: (String, Vec<u8>)) {
        let (key, body) = payload;
        let mut msg = Message::try_from(&body).unwrap();
        let origin = msg.get_origin();
        match RoutingKey::from(&key) {
            routing_key!(Chain >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_current_status(status);
                };
            }
            routing_key!(Synchronizer >> Status) => {
                if let Some(status) = msg.take_status() {
                    self.update_global_status(&status, origin);
                };
            }
            routing_key!(Synchronizer >> SyncResponse) => {
                if let Some(blocks) = msg.take_sync_response() {
                    self.process_sync(blocks);
                };
            }
            _ => {
                error!("receive: unexpected data key = {:?}", key);
            }
        }
    }

    // Initiate a sync request
    fn start_sync_req(&mut self, start_height: u64) {
        debug!(
            "sync: start_sync_req: start_height = {}, current height = {}",
            start_height,
            self.current_status.get_height()
        );
        let mut origin = 0;
        let mut end_height = start_height;
        let mut is_send = false;
        let current_height = self.current_status.get_height();

        if let Some((height, origins)) = self
            .latest_status_lists
            .iter()
            .rfind(|&(_, origins)| origins.len() > 0)
        {
            debug!(
                "sync: start_sync_req: height = {}, origins = {:?}",
                height, origins
            );
            if let Some(origins) = self.latest_status_lists.get(height) {
                if *height > current_height {
                    origin = origins[self.rand.gen_range(0, origins.len())];
                    end_height = if *height + 1 > current_height + SYNC_STEP {
                        current_height + SYNC_STEP
                    } else {
                        *height + 1
                    };
                    is_send = true;
                }
            }
        }

        if is_send {
            self.sync_strategy(start_height, end_height, origin);
        }
    }

    fn sync_strategy(&self, start_height: u64, end_height: u64, origin: u32) {
        //current height = 155,start_height = 156, end height = 160, to origin = 1
        debug!(
            "sync: sync_strategy: current height = {}, \
             start_height = {}, \
             end height = {}, \
             to origin = {}",
            self.current_status.get_height(),
            start_height,
            end_height,
            origin
        );
        if start_height >= self.current_status.get_height() && start_height <= end_height {
            let mut start_height = start_height;
            let mut step_sum = SYNC_STEP;
            let mut heights = vec![];

            while start_height <= end_height {
                if step_sum == 0 {
                    step_sum = SYNC_STEP;
                    self.send_sync_req(heights, origin);
                    heights = vec![];
                }
                heights.push(start_height);

                step_sum -= 1;
                start_height += 1;
            }
            self.send_sync_req(heights, origin);
        }
    }

    fn send_sync_req(&self, heights: Vec<u64>, origin: u32) {
        if !heights.is_empty() {
            debug!(
                "sync: send_sync_req:current height = {}, \
                 heights = {:?}, \
                 origin {:?}, \
                 chain.sync: OperateType {:?}",
                self.current_status.get_height(),
                heights,
                origin,
                OperateType::Single
            );
            let mut sync_req = SyncRequest::new();
            sync_req.set_heights(heights);
            let msg = Message::init(OperateType::Single, origin, sync_req.into());
            self.con
                .broadcast(routing_key!(Synchronizer >> SyncRequest).into(), msg);
        }
    }

    fn broadcast_status(&mut self) {
        debug!(
            "sync: broadcast status {:?}, {:?} to other nodes",
            self.current_status.get_height(),
            self.current_status.get_hash()
        );
        let msg: Message = self.current_status.clone().into();
        self.con
            .broadcast(routing_key!(Synchronizer >> Status).into(), msg);
    }

    // Submit synchronization information
    fn submit_blocks(&mut self) {
        let mut height = self.current_status.get_height() + 1;
        debug!(
            "sync: submit_blocks:submit_height = {},\
             current height = {},\
             sync_end_height = {},\
             block_lists = {}",
            height,
            self.current_status.get_height(),
            self.sync_end_height,
            self.block_lists.len()
        );
        let mut blocks = vec![];
        let end_height = height + SYNC_STEP;

        loop {
            if height <= end_height {
                if let Some(block) = self.block_lists.get(&height) {
                    blocks.push(block.to_owned());
                } else {
                    break;
                }
            } else {
                break;
            }
            height += 1;
        }

        match blocks.last() {
            Some(block) => {
                if let Some(header) = block.header.as_ref() {
                    let height = header.get_height() - 1;

                    if height > self.sync_end_height {
                        self.sync_end_height = height;
                    }
                }
            }
            None => {}
        }

        if self.block_lists.contains_key(&::std::u64::MAX) {
            blocks.push(self.block_lists.remove(&::std::u64::MAX).unwrap());
        }

        self.pub_blocks(blocks);
        self.is_synchronizing = true;
        self.remote_sync_time_out = Instant::now();
    }

    fn pub_blocks(&mut self, blocks: Vec<Block>) {
        if !blocks.is_empty() {
            debug!(
                "sync: pub_blocks: current height = {}, \
                 sync_end_height = {}, \
                 len = {}, ",
                self.current_status.get_height(),
                self.sync_end_height,
                blocks.len()
            );
            let mut sync_res = SyncResponse::new();
            sync_res.set_blocks(blocks.into());
            let msg: Message = sync_res.into();
            self.tx_pub.send((
                routing_key!(Net >> SyncResponse).into(),
                msg.try_into().unwrap(),
            ));
        }
    }

    fn add_latest_sync_lists(&mut self, height: u64, origin: u32) {
        debug!(
            "sync: add_sync_lists: current height = {}, \
             from node = {}, \
             height = {}",
            self.current_status.get_height(),
            origin,
            height
        );
        if self
            .latest_status_lists
            .entry(height)
            .or_insert_with(VecDeque::new)
            .iter()
            .fold(HashSet::new(), |mut set, item| {
                set.insert(item);
                set
            })
            .insert(&origin)
        {
            self.latest_status_lists
                .entry(height)
                .or_insert_with(VecDeque::new)
                .push_back(origin);
        }
    }

    /// Prune block on btreemap
    fn prune_block_list_cache(&mut self, height: u64) {
        self.block_lists = self.block_lists.split_off(&height);
    }
}
<|endoftext|>


<commit_before>//! Errors and error handling
//!
//! This mostly concerns converting to and from the main error type defined
//! in this crate: [`Error`](enum.Error.html)

use std::ffi::NulError;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::ops::Range;
use std::io;
use fitserror::FitsError;

/// Enumeration of all error types
#[derive(Debug)]
pub enum Error {
    /// Internal Fits errors
    Fits(FitsError),

    /// Invalid index error
    Index(IndexError),

    /// Generic errors from simple strings
    Message(String),

    /// String conversion errors
    Null(NulError),

    /// UTF-8 conversion errors
    Utf8(Utf8Error),

    /// IO errors
    Io(io::Error),
}

/// Error raised when the user requests invalid indexes for data
#[derive(Debug, PartialEq, Eq)]
pub struct IndexError {
    /// Error message
    pub message: String,

    /// The range requested by the user
    pub given: Range<usize>,
}

/// Handy error type for use internally
pub type Result<T> = ::std::result::Result<T, Error>;

impl ::std::convert::From<FitsError> for Error {
    fn from(error: FitsError) -> Self {
        Error::Fits(error)
    }
}

impl ::std::convert::From<IndexError> for Error {
    fn from(error: IndexError) -> Self {
        Error::Index(error)
    }
}

impl<'a> ::std::convert::From<&'a str> for Error {
    fn from(error: &'a str) -> Self {
        Error::Message(error.to_string())
    }
}

impl ::std::convert::From<NulError> for Error {
    fn from(error: NulError) -> Self {
        Error::Null(error)
    }
}

impl ::std::convert::From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Self {
        Error::Utf8(error.utf8_error())
    }
}

impl ::std::convert::From<Utf8Error> for Error {
    fn from(error: Utf8Error) -> Self {
        Error::Utf8(error)
    }
}

impl ::std::convert::From<Box<::std::error::Error>> for Error {
    fn from(error: Box<::std::error::Error>) -> Self {
        let description = error.description();
        let message = match error.cause() {
            Some(msg) => format!("Error: {} caused by {}", description, msg),
            None => format!("Error: {}", description),
        };
        Error::Message(message)
    }
}

impl ::std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Fits(ref e) => write!(f, "Fits error: {:?}", e),
            Error::Message(ref s) => write!(f, "Error: {}", s),
            Error::Null(ref e) => write!(f, "Error: {}", e),
            Error::Utf8(ref e) => write!(f, "Error: {}", e),
            Error::Index(ref e) => write!(f, "Error: {:?}", e),
            Error::Io(ref e) => e.fmt(f),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        "fitsio error"
    }
}
<commit_msg>Improve error display messages<commit_after>//! Errors and error handling
//!
//! This mostly concerns converting to and from the main error type defined
//! in this crate: [`Error`](enum.Error.html)

use std::ffi::NulError;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::ops::Range;
use std::io;
use fitserror::FitsError;

/// Enumeration of all error types
#[derive(Debug)]
pub enum Error {
    /// Internal Fits errors
    Fits(FitsError),

    /// Invalid index error
    Index(IndexError),

    /// Generic errors from simple strings
    Message(String),

    /// String conversion errors
    Null(NulError),

    /// UTF-8 conversion errors
    Utf8(Utf8Error),

    /// IO errors
    Io(io::Error),
}

/// Error raised when the user requests invalid indexes for data
#[derive(Debug, PartialEq, Eq)]
pub struct IndexError {
    /// Error message
    pub message: String,

    /// The range requested by the user
    pub given: Range<usize>,
}

/// Handy error type for use internally
pub type Result<T> = ::std::result::Result<T, Error>;

impl ::std::convert::From<FitsError> for Error {
    fn from(error: FitsError) -> Self {
        Error::Fits(error)
    }
}

impl ::std::convert::From<IndexError> for Error {
    fn from(error: IndexError) -> Self {
        Error::Index(error)
    }
}

impl<'a> ::std::convert::From<&'a str> for Error {
    fn from(error: &'a str) -> Self {
        Error::Message(error.to_string())
    }
}

impl ::std::convert::From<NulError> for Error {
    fn from(error: NulError) -> Self {
        Error::Null(error)
    }
}

impl ::std::convert::From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Self {
        Error::Utf8(error.utf8_error())
    }
}

impl ::std::convert::From<Utf8Error> for Error {
    fn from(error: Utf8Error) -> Self {
        Error::Utf8(error)
    }
}

impl ::std::convert::From<Box<::std::error::Error>> for Error {
    fn from(error: Box<::std::error::Error>) -> Self {
        let description = error.description();
        let message = match error.cause() {
            Some(msg) => format!("Error: {} caused by {}", description, msg),
            None => format!("Error: {}", description),
        };
        Error::Message(message)
    }
}

impl ::std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Fits(ref e) => write!(f, "Fits error: {:?}", e),
            Error::Message(ref s) => write!(f, "Error: {}", s),
            Error::Null(ref e) => e.fmt(f),
            Error::Utf8(ref e) => e.fmt(f),
            Error::Index(ref e) => write!(f, "Error: {:?}", e),
            Error::Io(ref e) => e.fmt(f),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        "fitsio error"
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// BSD 3-Clause license. For full terms please see the LICENSE file.

use utils::Status;

/// A structure for storing rpfram information
///
/// # Example
///
/// ```
/// use rpf::Prog;
///
/// static UTIL: Prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
/// assert_eq!(UTIL.name, "util");
/// assert_eq!(UTIL.vers, "0.1.0");
/// assert_eq!(UTIL.yr, "2015");
/// ```
pub struct Prog {
    /// Name of program
    pub name: &'static str,
    /// Version of program
    pub vers: &'static str,
    /// Year of copyright for program
    pub yr: &'static str,
}

impl Prog {
    /// Prints copyright, version, and author information
    ///
    /// # Example
    ///
    /// ```
    /// use rpf::Prog;
    ///
    /// let prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
    /// prog.copyright(
    /// "Copyright (C) 2015 util developers\n\
    /// License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\
    /// This is free software: you are free to change and redistribute it.\n\
    /// There is NO WARRANTY, to the extent permitted by law.\n", vec!["Author"]);
    /// ```
    ///
    /// Would print the following:
    ///
    /// ```bash
    /// util 0.1.0
    /// Copyright (C) 2015 util developers
    /// License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
    /// This is free software: you are free to change and redistribute it.
    /// There is NO WARRANTY, to the extent permitted by law.
    ///
    /// Written by Author
    /// ```
    pub fn copyright(&self, license: &str, auth: Vec<&str>) {
        print!("{} {}\n{}", &self.name, &self.vers, license);
        print!("Written by ");
        for pers in auth.iter() {
            print!("{} ", pers);
        }
        print!("\n");
    }

    /// Used for when no arguments are given to a util
    ///
    /// # Example
    ///
    /// ```should_panic
    /// use rpf::Prog;
    ///
    /// let prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
    /// prog.prog_try();
    /// ```
    ///
    /// Would print the following:
    ///
    /// ```bash
    /// util: Missing arguments
    /// Try util --help for more information
    /// ```
    pub fn prog_try(&self) {
        println!("{}: Missing arguments\n\
             Try '{} --help' for more information", &self.name, &self.name);
        Status::ArgError.exit();
    }
}

#[test]
fn test_prog_copyright() {
    let prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
    prog.copyright(
    "Copyright (C) 2015 util developers\n\
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\
    This is free software: you are free to change and redistribute it.\n\
    There is NO WARRANTY, to the extent permitted by law.\n", vec!["Author"]);
}
<commit_msg>prog: use array in place of vector<commit_after>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// BSD 3-Clause license. For full terms please see the LICENSE file.

use utils::Status;

/// A structure for storing rpfram information
///
/// # Example
///
/// ```
/// use rpf::Prog;
///
/// static UTIL: Prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
/// assert_eq!(UTIL.name, "util");
/// assert_eq!(UTIL.vers, "0.1.0");
/// assert_eq!(UTIL.yr, "2015");
/// ```
pub struct Prog {
    /// Name of program
    pub name: &'static str,
    /// Version of program
    pub vers: &'static str,
    /// Year of copyright for program
    pub yr: &'static str,
}

impl Prog {
    /// Prints copyright, version, and author information
    ///
    /// # Example
    ///
    /// ```
    /// use rpf::Prog;
    ///
    /// let prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
    /// prog.copyright(
    /// "Copyright (C) 2015 util developers\n\
    /// License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\
    /// This is free software: you are free to change and redistribute it.\n\
    /// There is NO WARRANTY, to the extent permitted by law.\n", &["Author"]);
    /// ```
    ///
    /// Would print the following:
    ///
    /// ```bash
    /// util 0.1.0
    /// Copyright (C) 2015 util developers
    /// License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
    /// This is free software: you are free to change and redistribute it.
    /// There is NO WARRANTY, to the extent permitted by law.
    ///
    /// Written by Author
    /// ```
    pub fn copyright(&self, license: &str, auth: &[&str]) {
        print!("{} {}\n{}", &self.name, &self.vers, license);
        print!("Written by ");
        for pers in auth.iter() {
            print!("{} ", pers);
        }
        print!("\n");
    }

    /// Used for when no arguments are given to a util
    ///
    /// # Example
    ///
    /// ```should_panic
    /// use rpf::Prog;
    ///
    /// let prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
    /// prog.prog_try();
    /// ```
    ///
    /// Would print the following:
    ///
    /// ```bash
    /// util: Missing arguments
    /// Try util --help for more information
    /// ```
    pub fn prog_try(&self) {
        println!("{}: Missing arguments\n\
             Try '{} --help' for more information", &self.name, &self.name);
        Status::ArgError.exit();
    }
}

#[test]
fn test_prog_copyright() {
    let prog = Prog { name: "util", vers: "0.1.0", yr: "2015" };
    prog.copyright(
    "Copyright (C) 2015 util developers\n\
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n\
    This is free software: you are free to change and redistribute it.\n\
    There is NO WARRANTY, to the extent permitted by law.\n", &["Author"]);
}
<|endoftext|>