<commit_before>use mem_map::*;
use device::Device;

#[allow(dead_code)] // TODO - remove when the rendering is written
const COLOUR_MAP: [u32; 4] = [0xff7e8429, 0xff527a4b, 0xff315d4b, 0xff29473e];
const WIDTH: usize = 160;
const HEIGHT: usize = 144;

pub struct Gpu {
    vram: Box<[u8]>, // VRAM - mapped to 0x8000 - 0x9FFF
    obj_attr_table: Box<[u8]>, // Obj/Sprite Attribute Table (OAM) - mapped to 0xfe00 - 0xfea0
    frame_buffer: Box<[u32]>,

    lcd_control: LcdControlReg, // 0xff40 - LCDC
    lcdc_status: LcdcStatusReg, // 0xff41 - STAT
    scy: u8, // 0xff42 - SCY scroll background Y position
    scx: u8, // 0xff43 - SCX scroll background X position
    ly: u8, // 0xff44 - LY scanline being sent to LCD driver, reset on write
    lyc: u8, // 0xff45 - LYC if equal to LY STAT.coincident is set
    dma_transfer: u8, // 0xff46 - when set initiates DMA transfer (~160 microseconds)
    bg_palette_data: PaletteDataReg, // 0xff47 - BG & Window palette data
    obj0_palette_data: PaletteDataReg, // 0xff48 OBJ0 palette data
    obj1_palette_data: PaletteDataReg, // 0xff49 OBJ1 palette data
    wy: u8, // 0xff4a - window Y position
    wx: u8, // 0xff4b - window X position, offset from screen coords by 7

    cycles: u16,
}

impl Gpu {
    pub fn new() -> Self {
        Gpu {
            vram: vec![0; VRAM_LENGTH as usize].into_boxed_slice(),
            obj_attr_table: vec![0; OAM_LENGTH as usize].into_boxed_slice(),
            frame_buffer: vec![COLOUR_MAP[0]; WIDTH * HEIGHT].into_boxed_slice(),

            lcd_control: LcdControlReg::default(),
            lcdc_status: LcdcStatusReg::default(),
            scy: 0,
            scx: 0,
            ly: 0,
            lyc: 0,
            wy: 0,
            wx: 0,
            bg_palette_data: PaletteDataReg::default(),
            obj0_palette_data: PaletteDataReg::default(),
            obj1_palette_data: PaletteDataReg::default(),
            dma_transfer: 0,

            cycles: 0,
        }
    }

    pub fn read_vram(&self, addr: u16) -> u8 {
        self.vram[addr as usize]
    }

    pub fn write_vram(&mut self, addr: u16, val: u8) {
        self.vram[addr as usize] = val;
    }

    pub fn read_oam(&self, addr: u16) -> u8 {
        self.obj_attr_table[addr as usize]
    }

    pub fn write_oam(&mut self, addr: u16, val: u8) {
        self.obj_attr_table[addr as usize] = val;
    }

    pub fn read_reg(&self, addr: u16) -> u8 {
        match addr {
            0xff40 => self.lcd_control.into(),
            0xff41 => self.lcdc_status.into(),
            0xff42 => self.scy,
            0xff43 => self.scx,
            0xff44 => self.ly,
            0xff45 => self.lyc,
            0xff46 => self.dma_transfer,
            0xff47 => self.bg_palette_data.into(),
            0xff48 => self.obj0_palette_data.into(),
            0xff49 => self.obj1_palette_data.into(),
            0xff4a => self.wy,
            0xff4b => self.wx,
            _ => 0xff, // reads from unused addresses return 0xff
        }
    }

    pub fn write_reg(&mut self, addr: u16, val: u8) {
        match addr {
            0xff40 => self.lcd_control = val.into(),
            0xff41 => self.lcdc_status = val.into(),
            0xff42 => self.scy = val,
            0xff43 => self.scx = val,
            0xff44 => self.ly = val,
            0xff45 => self.lyc = val,
            0xff46 => self.dma_transfer = val,
            0xff47 => self.bg_palette_data = val.into(),
            0xff48 => self.obj0_palette_data = val.into(),
            0xff49 => self.obj1_palette_data = val.into(),
            0xff4a => self.wy = val,
            0xff4b => self.wx = val,
            _ => {
                panic!("Write to non-gpu register in gpu {:04x} = {:02x}",
                       addr,
                       val)
            }
        }
    }

    pub fn step(&mut self, cycles: u16, device: &mut Device) -> u8 {
        if !self.lcd_control.lcd_control_op {
            return 0;
        }

        let mut ret = 0;
        for _ in 0..cycles {
            ret |= self.inner_step(device);
        }

        ret
    }

    pub fn get_width(&self) -> usize {
        WIDTH
    }

    pub fn get_height(&self) -> usize {
        HEIGHT
    }

    fn inner_step(&mut self, device: &mut Device) -> u8 {
        let mut ret = 0;
        self.cycles += 1;

        if self.lcdc_status.mode == 0 && self.cycles == 4 {
            if self.ly < 144 {
                self.lcdc_status.mode = 2;
            } else {
                self.lcdc_status.mode = 1;

                ret |= 0x01;

                device.set_frame_buffer(&self.frame_buffer);
            }
        } else if self.lcdc_status.mode == 0 && self.cycles == 456 {
            self.ly += 1;
            self.cycles = 0;
        } else if self.lcdc_status.mode == 1 {
            if self.cycles == 456 {
                self.cycles = 0;

                if self.ly == 0 {
                    self.lcdc_status.mode = 0;
                } else {
                    self.ly += 1;
                }
            } else if self.ly == 153 && self.cycles == 5 {
                self.ly = 0;
            }
        } else if self.lcdc_status.mode == 2 && self.cycles == 85 {
            self.lcdc_status.mode = 3;

            self.render_background();
        } else if self.lcdc_status.mode == 3 && self.cycles == 260 {
            // TODO - this mode should have variable length
            self.lcdc_status.mode = 0
        }

        ret
    }

    fn render_background(&mut self) {
        let background_row = self.ly.wrapping_add(self.scy);

        for i in 0..WIDTH as u8 {
            let background_col = self.scx.wrapping_add(i);

            let tile_offset = self.get_background_tile_offset(background_row / 8,
                                                              background_col / 8);
            let colour = self.get_tile_pixel(tile_offset, background_row % 8, background_col % 8);

            self.frame_buffer[(self.ly as usize * WIDTH) + i as usize] = colour;
        }
    }

    // Returns the offset in self.vram of the background tile
    fn get_background_tile_offset(&self, row: u8, col: u8) -> usize {
        let tile_idx_base = if self.lcd_control.bg_tile_map_display {
            0x1c00
        } else {
            0x1800
        };
        let tile_idx_offset = (row as usize * 32) + col as usize;
        let tile_index = self.vram[tile_idx_base + tile_idx_offset];

        if self.lcd_control.bg_win_tile_data {
            tile_index as usize * 16
        } else {
            (((tile_index as i8) as isize) + 256) as usize * 16
        }
    }

    fn get_tile_pixel(&self, tile_offset: usize, row: u8, col: u8) -> u32 {
        let offset = tile_offset + (row as usize * 2);

        let upper_col = self.vram[offset + 1] >> (7 - col) & 1;
        let lower_col = self.vram[offset] >> (7 - col) & 1;
        let tile_colour = upper_col << 1 | lower_col;

        let col_index = match tile_colour {
            0 => self.bg_palette_data.col0_shade,
            1 => self.bg_palette_data.col1_shade,
            2 => self.bg_palette_data.col2_shade,
            3 => self.bg_palette_data.col3_shade,
            _ => unreachable!(),
        };
        COLOUR_MAP[col_index]
    }
}

#[derive(Default, Copy, Clone)]
pub struct LcdControlReg {
    bg_window_display: bool,
    obj_display: bool,
    obj_size: bool,
    bg_tile_map_display: bool,
    bg_win_tile_data: bool,
    window_display: bool,
    win_tile_map_display: bool,
    lcd_control_op: bool,
}

impl From<u8> for LcdControlReg {
    fn from(val: u8) -> Self {
        LcdControlReg {
            bg_window_display: val & 1 != 0,
            obj_display: val & (1 << 1) != 0,
            obj_size: val & (1 << 2) != 0,
            bg_tile_map_display: val & (1 << 3) != 0,
            bg_win_tile_data: val & (1 << 4) != 0,
            window_display: val & (1 << 5) != 0,
            win_tile_map_display: val & (1 << 6) != 0,
            lcd_control_op: val & (1 << 7) != 0,
        }
    }
}

impl Into<u8> for LcdControlReg {
    fn into(self) -> u8 {
        let mut ret: u8 = 0;
        if self.bg_window_display {
            ret |= 1;
        }
        if self.obj_display {
            ret |= 1 << 1;
        }
        if self.obj_size {
            ret |= 1 << 2;
        }
        if self.bg_tile_map_display {
            ret |= 1 << 3;
        }
        if self.bg_win_tile_data {
            ret |= 1 << 4;
        }
        if self.window_display {
            ret |= 1 << 5;
        }
        if self.win_tile_map_display {
            ret |= 1 << 6;
        }
        if self.lcd_control_op {
            ret |= 1 << 7;
        }
        ret
    }
}

#[derive(Default, Copy, Clone)]
pub struct LcdcStatusReg {
    coincidence_interrupt_enable: bool,
    oam_interrupt_enable: bool,
    vblank_interrupt_enable: bool,
    hblank_interrupt_enable: bool,
    coincidence_flag: bool,
    mode: u8,
}

impl From<u8> for LcdcStatusReg {
    fn from(val: u8) -> Self {
        LcdcStatusReg {
            coincidence_interrupt_enable: val & (1 << 6) != 0,
            oam_interrupt_enable: val & (1 << 5) != 0,
            vblank_interrupt_enable: val & (1 << 4) != 0,
            hblank_interrupt_enable: val & (1 << 3) != 0,
            coincidence_flag: val & (1 << 2) != 0,
            mode: val & 0x3,
        }
    }
}

impl Into<u8> for LcdcStatusReg {
    fn into(self) -> u8 {
        let mut ret = self.mode;

        if self.coincidence_interrupt_enable {
            ret |= 1 << 6;
        }
        if self.oam_interrupt_enable {
            ret |= 1 << 5;
        }
        if self.vblank_interrupt_enable {
            ret |= 1 << 4;
        }
        if self.hblank_interrupt_enable {
            ret |= 1 << 3;
        }
        if self.coincidence_flag {
            ret |= 1 << 2;
        }
        ret
    }
}

#[derive(Default, Copy, Clone)]
pub struct PaletteDataReg {
    col0_shade: usize,
    col1_shade: usize,
    col2_shade: usize,
    col3_shade: usize,
}

impl From<u8> for PaletteDataReg {
    fn from(val: u8) -> Self {
        let val = val as usize;
        PaletteDataReg {
            col0_shade: val & 0x3,
            col1_shade: (val >> 2) & 0x3,
            col2_shade: (val >> 4) & 0x3,
            col3_shade: (val >> 6) & 0x3,
        }
    }
}

impl Into<u8> for PaletteDataReg {
    fn into(self) -> u8 {
        (self.col0_shade | (self.col1_shade << 2) | (self.col2_shade << 4) |
         (self.col3_shade << 6)) as u8
    }
}
<commit_msg>Basic support for sprites<commit_after>use mem_map::*;
use device::Device;

#[allow(dead_code)] // TODO - remove when the rendering is written
const COLOUR_MAP: [u32; 4] = [0xff7e8429, 0xff527a4b, 0xff315d4b, 0xff29473e];
const WIDTH: usize = 160;
const HEIGHT: usize = 144;

pub struct Gpu {
    vram: Box<[u8]>, // VRAM - mapped to 0x8000 - 0x9FFF
    oam: Box<[u8]>, // Obj/Sprite Attribute Table - mapped to 0xfe00 - 0xfea0
    frame_buffer: Box<[u32]>,

    lcd_control: LcdControlReg, // 0xff40 - LCDC
    lcdc_status: LcdcStatusReg, // 0xff41 - STAT
    scy: u8, // 0xff42 - SCY scroll background Y position
    scx: u8, // 0xff43 - SCX scroll background X position
    ly: u8, // 0xff44 - LY scanline being sent to LCD driver, reset on write
    lyc: u8, // 0xff45 - LYC if equal to LY STAT.coincident is set
    dma_transfer: u8, // 0xff46 - when set initiates DMA transfer (~160 microseconds)
    bg_palette_data: PaletteDataReg, // 0xff47 - BG & Window palette data
    obj0_palette_data: PaletteDataReg, // 0xff48 OBJ0 palette data
    obj1_palette_data: PaletteDataReg, // 0xff49 OBJ1 palette data
    wy: u8, // 0xff4a - window Y position
    wx: u8, // 0xff4b - window X position, offset from screen coords by 7

    cycles: u16,
}

impl Gpu {
    pub fn new() -> Self {
        Gpu {
            vram: vec![0; VRAM_LENGTH as usize].into_boxed_slice(),
            oam: vec![0; OAM_LENGTH as usize].into_boxed_slice(),
            frame_buffer: vec![COLOUR_MAP[0]; WIDTH * HEIGHT].into_boxed_slice(),

            lcd_control: LcdControlReg::default(),
            lcdc_status: LcdcStatusReg::default(),
            scy: 0,
            scx: 0,
            ly: 0,
            lyc: 0,
            wy: 0,
            wx: 0,
            bg_palette_data: PaletteDataReg::default(),
            obj0_palette_data: PaletteDataReg::default(),
            obj1_palette_data: PaletteDataReg::default(),
            dma_transfer: 0,

            cycles: 0,
        }
    }

    pub fn read_vram(&self, addr: u16) -> u8 {
        self.vram[addr as usize]
    }

    pub fn write_vram(&mut self, addr: u16, val: u8) {
        self.vram[addr as usize] = val;
    }

    pub fn read_oam(&self, addr: u16) -> u8 {
        self.oam[addr as usize]
    }

    pub fn write_oam(&mut self, addr: u16, val: u8) {
        self.oam[addr as usize] = val;
    }

    pub fn read_reg(&self, addr: u16) -> u8 {
        match addr {
            0xff40 => self.lcd_control.into(),
            0xff41 => self.lcdc_status.into(),
            0xff42 => self.scy,
            0xff43 => self.scx,
            0xff44 => self.ly,
            0xff45 => self.lyc,
            0xff46 => self.dma_transfer,
            0xff47 => self.bg_palette_data.into(),
            0xff48 => self.obj0_palette_data.into(),
            0xff49 => self.obj1_palette_data.into(),
            0xff4a => self.wy,
            0xff4b => self.wx,
            _ => 0xff, // reads from unused addresses return 0xff
        }
    }

    pub fn write_reg(&mut self, addr: u16, val: u8) {
        match addr {
            0xff40 => self.lcd_control = val.into(),
            0xff41 => self.lcdc_status = val.into(),
            0xff42 => self.scy = val,
            0xff43 => self.scx = val,
            0xff44 => self.ly = val,
            0xff45 => self.lyc = val,
            0xff46 => self.dma_transfer = val,
            0xff47 => self.bg_palette_data = val.into(),
            0xff48 => self.obj0_palette_data = val.into(),
            0xff49 => self.obj1_palette_data = val.into(),
            0xff4a => self.wy = val,
            0xff4b => self.wx = val,
            _ => {
                panic!("Write to non-gpu register in gpu {:04x} = {:02x}",
                       addr,
                       val)
            }
        }
    }

    pub fn step(&mut self, cycles: u16, device: &mut Device) -> u8 {
        if !self.lcd_control.lcd_control_op {
            return 0;
        }

        let mut ret = 0;
        for _ in 0..cycles {
            ret |= self.inner_step(device);
        }

        ret
    }

    pub fn get_width(&self) -> usize {
        WIDTH
    }

    pub fn get_height(&self) -> usize {
        HEIGHT
    }

    fn inner_step(&mut self, device: &mut Device) -> u8 {
        let mut ret = 0;
        self.cycles += 1;

        if self.lcdc_status.mode == 0 && self.cycles == 4 {
            if self.ly < 144 {
                self.lcdc_status.mode = 2;
            } else {
                self.lcdc_status.mode = 1;

                ret |= 0x01;

                device.set_frame_buffer(&self.frame_buffer);
            }
        } else if self.lcdc_status.mode == 0 && self.cycles == 456 {
            self.ly += 1;
            self.cycles = 0;
        } else if self.lcdc_status.mode == 1 {
            if self.cycles == 456 {
                self.cycles = 0;

                if self.ly == 0 {
                    self.lcdc_status.mode = 0;
                } else {
                    self.ly += 1;
                }
            } else if self.ly == 153 && self.cycles == 5 {
                self.ly = 0;
            }
        } else if self.lcdc_status.mode == 2 && self.cycles == 85 {
            self.lcdc_status.mode = 3;

            self.render_background();

            if self.lcd_control.sprite_display {
                self.render_sprites();
            }
        } else if self.lcdc_status.mode == 3 && self.cycles == 260 {
            // TODO - this mode should have variable length
            self.lcdc_status.mode = 0
        }

        ret
    }

    fn render_background(&mut self) {
        let background_row = self.ly.wrapping_add(self.scy);

        for i in 0..WIDTH as u8 {
            let background_col = self.scx.wrapping_add(i);

            let tile_offset = self.get_background_tile_offset(background_row / 8,
                                                              background_col / 8);
            let colour = self.get_tile_pixel(tile_offset, background_row % 8, background_col % 8);

            self.frame_buffer[(self.ly as usize * WIDTH) + i as usize] = colour;
        }
    }

    fn render_sprites(&mut self) {
        let sprite_height: i16 = if self.lcd_control.sprite_size { 16 } else { 8 };
        let ly = self.ly as i16;

        for i in 0..40 {
            let sprite_y = (self.oam[i * 4] as i16) - 16;

            if ly < sprite_y || (sprite_y + sprite_height - 1) < ly {
                continue
            }

            let sprite_row = (ly - sprite_y) as usize;
            let sprite_x = (self.oam[(i * 4) + 1] as i16) - 8;
            let tile_index = self.oam[(i * 4) + 2] as usize;
            let tile_offset = tile_index * (sprite_height as usize) * 2;

            for i in 0..8 {
                let colour = self.get_sprite_pixel(tile_offset, sprite_row, i);

                self.frame_buffer[(ly as usize * WIDTH) + (sprite_x + i as i16) as usize] = colour;
            }
        }
    }

    // Returns the offset in self.vram of the background tile
    fn get_background_tile_offset(&self, row: u8, col: u8) -> usize {
        let tile_idx_base = if self.lcd_control.bg_tile_map_display {
            0x1c00
        } else {
            0x1800
        };
        let tile_idx_offset = (row as usize * 32) + col as usize;
        let tile_index = self.vram[tile_idx_base + tile_idx_offset];

        if self.lcd_control.bg_win_tile_data {
            tile_index as usize * 16
        } else {
            (((tile_index as i8) as isize) + 256) as usize * 16
        }
    }

    fn get_tile_pixel(&self, tile_offset: usize, row: u8, col: u8) -> u32 {
        let offset = tile_offset + (row as usize * 2);

        let upper_col = self.vram[offset + 1] >> (7 - col) & 1;
        let lower_col = self.vram[offset] >> (7 - col) & 1;
        let tile_colour = upper_col << 1 | lower_col;

        let col_index = match tile_colour {
            0 => self.bg_palette_data.col0_shade,
            1 => self.bg_palette_data.col1_shade,
            2 => self.bg_palette_data.col2_shade,
            3 => self.bg_palette_data.col3_shade,
            _ => unreachable!(),
        };
        COLOUR_MAP[col_index]
    }

    fn get_sprite_pixel(&self, tile_offset: usize, row: usize, col: usize) -> u32 {
        let offset = tile_offset + (row as usize * 2);

        let upper_col = self.vram[offset + 1] >> (7 - col) & 1;
        let lower_col = self.vram[offset] >> (7 - col) & 1;
        let tile_colour = upper_col << 1 | lower_col;

        let col_index = match tile_colour {
            0 => self.obj0_palette_data.col0_shade,
            1 => self.obj0_palette_data.col1_shade,
            2 => self.obj0_palette_data.col2_shade,
            3 => self.obj0_palette_data.col3_shade,
            _ => unreachable!(),
        };
        COLOUR_MAP[col_index]
    }
}

#[derive(Default, Copy, Clone)]
pub struct LcdControlReg {
    bg_window_display: bool,
    sprite_display: bool,
    sprite_size: bool,
    bg_tile_map_display: bool,
    bg_win_tile_data: bool,
    window_display: bool,
    win_tile_map_display: bool,
    lcd_control_op: bool,
}

impl From<u8> for LcdControlReg {
    fn from(val: u8) -> Self {
        LcdControlReg {
            bg_window_display: val & 1 != 0,
            sprite_display: val & (1 << 1) != 0,
            sprite_size: val & (1 << 2) != 0,
            bg_tile_map_display: val & (1 << 3) != 0,
            bg_win_tile_data: val & (1 << 4) != 0,
            window_display: val & (1 << 5) != 0,
            win_tile_map_display: val & (1 << 6) != 0,
            lcd_control_op: val & (1 << 7) != 0,
        }
    }
}

impl Into<u8> for LcdControlReg {
    fn into(self) -> u8 {
        let mut ret: u8 = 0;
        if self.bg_window_display {
            ret |= 1;
        }
        if self.sprite_display {
            ret |= 1 << 1;
        }
        if self.sprite_size {
            ret |= 1 << 2;
        }
        if self.bg_tile_map_display {
            ret |= 1 << 3;
        }
        if self.bg_win_tile_data {
            ret |= 1 << 4;
        }
        if self.window_display {
            ret |= 1 << 5;
        }
        if self.win_tile_map_display {
            ret |= 1 << 6;
        }
        if self.lcd_control_op {
            ret |= 1 << 7;
        }
        ret
    }
}

#[derive(Default, Copy, Clone)]
pub struct LcdcStatusReg {
    coincidence_interrupt_enable: bool,
    oam_interrupt_enable: bool,
    vblank_interrupt_enable: bool,
    hblank_interrupt_enable: bool,
    coincidence_flag: bool,
    mode: u8,
}

impl From<u8> for LcdcStatusReg {
    fn from(val: u8) -> Self {
        LcdcStatusReg {
            coincidence_interrupt_enable: val & (1 << 6) != 0,
            oam_interrupt_enable: val & (1 << 5) != 0,
            vblank_interrupt_enable: val & (1 << 4) != 0,
            hblank_interrupt_enable: val & (1 << 3) != 0,
            coincidence_flag: val & (1 << 2) != 0,
            mode: val & 0x3,
        }
    }
}

impl Into<u8> for LcdcStatusReg {
    fn into(self) -> u8 {
        let mut ret = self.mode;

        if self.coincidence_interrupt_enable {
            ret |= 1 << 6;
        }
        if self.oam_interrupt_enable {
            ret |= 1 << 5;
        }
        if self.vblank_interrupt_enable {
            ret |= 1 << 4;
        }
        if self.hblank_interrupt_enable {
            ret |= 1 << 3;
        }
        if self.coincidence_flag {
            ret |= 1 << 2;
        }
        ret
    }
}

#[derive(Default, Copy, Clone)]
pub struct PaletteDataReg {
    col0_shade: usize,
    col1_shade: usize,
    col2_shade: usize,
    col3_shade: usize,
}

impl From<u8> for PaletteDataReg {
    fn from(val: u8) -> Self {
        let val = val as usize;
        PaletteDataReg {
            col0_shade: val & 0x3,
            col1_shade: (val >> 2) & 0x3,
            col2_shade: (val >> 4) & 0x3,
            col3_shade: (val >> 6) & 0x3,
        }
    }
}

impl Into<u8> for PaletteDataReg {
    fn into(self) -> u8 {
        (self.col0_shade | (self.col1_shade << 2) | (self.col2_shade << 4) |
         (self.col3_shade << 6)) as u8
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::to_str::ToStr;
use std::os::pipe;
use std::io::{Open, Write};
use std::io::fs::{mkdir, File};
use std::io::pipe::PipeStream;
use std::io::stdio::{stdout, stderr};

use argparse::{ArgumentParser, Store, List};

use super::env::Environ;
use super::config::Config;
use super::linux::{make_namespace, change_root, bind_mount, mount_pseudofs};
use super::linux::{execute, forkme, wait_process};
use libc::funcs::posix88::unistd::getuid;

fn mount_all(root: &Path, mount_dir: &Path, project_root: &Path)
    -> Result<(), String>
{
    let vagga_marker = mount_dir.join_many(["tmp", ".vagga"]);
    try!(bind_mount(root, mount_dir, false));
    try!(bind_mount(&Path::new("/sys"), &mount_dir.join("sys"), false));
    // TODO(tailhook) use dev in /var/lib/container-dev
    try!(bind_mount(&Path::new("/dev"), &mount_dir.join("dev"), false));
    try!(bind_mount(project_root, &mount_dir.join("work"), true));
    try!(mount_pseudofs("proc", &mount_dir.join("proc"), ""));
    // TODO(tailhook) allow customize size of tmpfs
    try!(mount_pseudofs("tmpfs", &mount_dir.join("tmp"),
                        "size=102400k,mode=1777"));
    try!(ensure_dir(&vagga_marker));
    try!(bind_mount(&vagga_marker,
                    &mount_dir.join_many(["work", ".vagga"]),
                    false));
    match File::open_mode(&vagga_marker.join("CONTAINED.txt"), Open, Write)
        .write_line("You are running in vagga container.") {
        Ok(()) => {}
        Err(e) => return Err(format!("Can't write CONTAINED.txt: {}", e)),
    }
    return Ok(());
}

fn ensure_dir(p: &Path) -> Result<(),String> {
    if p.exists() {
        return Ok(());
    }
    return mkdir(p, io::UserRWX).map_err(|e| { e.to_str() });
}

pub fn run_chroot(env: &Environ, container_root: &Path, mount_dir: &Path,
    command: &String, args: &Vec<String>)
    -> Result<(),String>
{
    try!(mount_all(container_root, mount_dir, &env.project_root));
    try!(change_root(mount_dir));
    // TODO(tailhook) set environment from config
    let environ = vec!(
        "PATH=/bin:/usr/bin:/usr/local/bin".to_string(),
        "HOME=/non-existent".to_string(),
        );
    try!(execute(command, args, &environ));
    unreachable!();
}

pub fn run_user_command(env: &Environ, config: &Config,
    cmdname: &String, args: Vec<String>)
    -> Result<int, String>
{
    let command = match config.commands.find(cmdname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find command {} in config",
                               cmdname));
        }
    };
    let cname = match command.container {
        Some(ref name) => name.clone(),
        None => unimplemented!(),
    };
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} for command {}",
                               command.container, cmdname));
        }
    };
    return match command.run {
        Some(ref cmdline) => _run(env, config, &cname,
            &"/bin/sh".to_string(),
            &(vec!("-c".to_string(), cmdline.clone()) + args.slice_from(1))),
        None => unimplemented!()
    }
}

pub fn run_command(env: &Environ, config: &Config, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut command = "".to_string();
    let mut cmdargs = Vec::new();
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut command)
            .add_argument("command", box Store::<String>,
                "A command to run inside container")
            .required();
        ap.refer(&mut cmdargs)
            .add_argument("arguments", box List::<String>,
                "Arguments for the command")
            .required();
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} in config",
                               cname));
        }
    };
    _run(env, config, &cname, &command, &cmdargs)
}

pub fn _run(env: &Environ, config: &Config, container: &String,
    command: &String, cmdargs: &Vec<String>)
    -> Result<int, String>
{
    info!("Running {}: {} {}", container, command, cmdargs);
    let container_dir = env.project_root.join_many(
        [".vagga", container.as_slice()]);
    let container_root = container_dir.join("root");
    let uid = unsafe { getuid() };

    for dir in ["proc", "sys", "dev", "work", "tmp"].iter() {
        try!(ensure_dir(&container_root.join(*dir)));
    }

    let mount_dir = env.project_root.join_many([".vagga", "mnt"]);
    try!(ensure_dir(&mount_dir));
    try!(make_namespace());

    let mut pipe = match PipeStream::pair() {
        Ok(pipe) => pipe,
        Err(x) => return Err(format!("Can't create pipe: {}", x)),
    };

    let pid = try!(forkme());
    if pid == 0 {
        let mut buf: [u8,..1] = [0];
        match pipe.reader.read(buf) {
            Ok(_) => {}
            Err(x) => return Err(format!("Can't read from pipe: {}", x)),
        }
        drop(pipe);
        try!(run_chroot(env, &container_root, &mount_dir, command, cmdargs));
        unreachable!();
    } else {
        // TODO(tailhook) set uid map from config
        let uid_map = format!("0 {} 1", uid);
        debug!("Writing uid_map: {}", uid_map);
        match File::open_mode(&Path::new("/proc")
                          .join(pid.to_str())
                          .join("uid_map"), Open, Write)
                .write_str(uid_map.as_slice()) {
            Ok(()) => {}
            Err(e) => return Err(format!(
                "Error writing uid mapping: {}", e)),
        }

        match pipe.writer.write_char('x') {
            Ok(_) => {}
            Err(e) => return Err(format!(
                "Error writing to pipe: {}", e)),
        }
        drop(pipe);

        return wait_process(pid);
    }
}
<commit_msg>Implement proper change_dir handling<commit_after>use std::io;
use std::to_str::ToStr;
use std::os::{pipe, change_dir};
use std::io::{Open, Write};
use std::io::fs::{mkdir, File};
use std::io::pipe::PipeStream;
use std::io::stdio::{stdout, stderr};

use argparse::{ArgumentParser, Store, List};

use super::env::Environ;
use super::config::Config;
use super::linux::{make_namespace, change_root, bind_mount, mount_pseudofs};
use super::linux::{execute, forkme, wait_process};
use libc::funcs::posix88::unistd::getuid;

fn mount_all(root: &Path, mount_dir: &Path, project_root: &Path)
    -> Result<(), String>
{
    let vagga_marker = mount_dir.join_many(["tmp", ".vagga"]);
    try!(bind_mount(root, mount_dir, false));
    try!(bind_mount(&Path::new("/sys"), &mount_dir.join("sys"), false));
    // TODO(tailhook) use dev in /var/lib/container-dev
    try!(bind_mount(&Path::new("/dev"), &mount_dir.join("dev"), false));
    try!(bind_mount(project_root, &mount_dir.join("work"), true));
    try!(mount_pseudofs("proc", &mount_dir.join("proc"), ""));
    // TODO(tailhook) allow customize size of tmpfs
    try!(mount_pseudofs("tmpfs", &mount_dir.join("tmp"),
                        "size=102400k,mode=1777"));
    try!(ensure_dir(&vagga_marker));
    try!(bind_mount(&vagga_marker,
                    &mount_dir.join_many(["work", ".vagga"]),
                    false));
    match File::open_mode(&vagga_marker.join("CONTAINED.txt"), Open, Write)
        .write_line("You are running in vagga container.") {
        Ok(()) => {}
        Err(e) => return Err(format!("Can't write CONTAINED.txt: {}", e)),
    }
    return Ok(());
}

fn ensure_dir(p: &Path) -> Result<(),String> {
    if p.exists() {
        return Ok(());
    }
    return mkdir(p, io::UserRWX).map_err(|e| { e.to_str() });
}

pub fn run_chroot(env: &Environ, container_root: &Path, mount_dir: &Path,
    command: &String, args: &Vec<String>)
    -> Result<(),String>
{
    try!(mount_all(container_root, mount_dir, &env.project_root));
    debug!("Changing directory to {}", mount_dir.display());
    change_dir(mount_dir);
    try!(change_root(mount_dir));
    let reldir = match env.work_dir.path_relative_from(&env.project_root) {
        Some(path) => path,
        None => Path::new(""),
    };
    let path = Path::new("/work").join(reldir);
    debug!("Changing directory to {}", path.display());
    change_dir(&path);

    // TODO(tailhook) set environment from config
    let environ = vec!(
        "PATH=/bin:/usr/bin:/usr/local/bin".to_string(),
        "HOME=/non-existent".to_string(),
        );
    try!(execute(command, args, &environ));
    unreachable!();
}

pub fn run_user_command(env: &Environ, config: &Config,
    cmdname: &String, args: Vec<String>)
    -> Result<int, String>
{
    let command = match config.commands.find(cmdname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find command {} in config",
                               cmdname));
        }
    };
    let cname = match command.container {
        Some(ref name) => name.clone(),
        None => unimplemented!(),
    };
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} for command {}",
                               command.container, cmdname));
        }
    };
    return match command.run {
        Some(ref cmdline) => _run(env, config, &cname,
            &"/bin/sh".to_string(),
            &(vec!("-c".to_string(), cmdline.clone()) + args.slice_from(1))),
        None => unimplemented!()
    }
}

pub fn run_command(env: &Environ, config: &Config, args: Vec<String>)
    -> Result<int, String>
{
    let mut cname = "devel".to_string();
    let mut command = "".to_string();
    let mut cmdargs = Vec::new();
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut cname)
            .add_argument("container", box Store::<String>,
                "A name of the container to build")
            .required();
        ap.refer(&mut command)
            .add_argument("command", box Store::<String>,
                "A command to run inside container")
            .required();
        ap.refer(&mut cmdargs)
            .add_argument("arguments", box List::<String>,
                "Arguments for the command")
            .required();
        match ap.parse(args, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => return Ok(122),
        }
    }
    match config.containers.find(&cname) {
        Some(c) => c,
        None => {
            return Err(format!("Can't find container {} in config",
                               cname));
        }
    };
    _run(env, config, &cname, &command, &cmdargs)
}

pub fn _run(env: &Environ, config: &Config, container: &String,
    command: &String, cmdargs: &Vec<String>)
    -> Result<int, String>
{
    info!("Running {}: {} {}", container, command, cmdargs);
    let container_dir = env.project_root.join_many(
        [".vagga", container.as_slice()]);
    let container_root = container_dir.join("root");
    let uid = unsafe { getuid() };

    for dir in ["proc", "sys", "dev", "work", "tmp"].iter() {
        try!(ensure_dir(&container_root.join(*dir)));
    }

    let mount_dir = env.project_root.join_many([".vagga", "mnt"]);
    try!(ensure_dir(&mount_dir));
    try!(make_namespace());

    let mut pipe = match PipeStream::pair() {
        Ok(pipe) => pipe,
        Err(x) => return Err(format!("Can't create pipe: {}", x)),
    };

    let pid = try!(forkme());
    if pid == 0 {
        let mut buf: [u8,..1] = [0];
        match pipe.reader.read(buf) {
            Ok(_) => {}
            Err(x) => return Err(format!("Can't read from pipe: {}", x)),
        }
        drop(pipe);
        try!(run_chroot(env, &container_root, &mount_dir, command, cmdargs));
        unreachable!();
    } else {
        // TODO(tailhook) set uid map from config
        let uid_map = format!("0 {} 1", uid);
        debug!("Writing uid_map: {}", uid_map);
        match File::open_mode(&Path::new("/proc")
                          .join(pid.to_str())
                          .join("uid_map"), Open, Write)
                .write_str(uid_map.as_slice()) {
            Ok(()) => {}
            Err(e) => return Err(format!(
                "Error writing uid mapping: {}", e)),
        }

        match pipe.writer.write_char('x') {
            Ok(_) => {}
            Err(e) => return Err(format!(
                "Error writing to pipe: {}", e)),
        }
        drop(pipe);

        return wait_process(pid);
    }
}
<|endoftext|>


<commit_before>//! Sqlite specific expression methods.

use super::operators::*;
use crate::dsl;
use crate::expression::grouped::Grouped;
use crate::expression::{AsExpression, Expression};
use crate::sql_types::SqlType;

/// Sqlite specific methods which are present on all expressions.
pub trait SqliteExpressionMethods: Expression + Sized {
    /// Creates a Sqlite `IS` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// let jack_is_a_dog = animals
    ///     .select(name)
    ///     .filter(species.is("dog"))
    ///     .get_results::<Option<String>>(&connection)?;
    /// assert_eq!(vec![Some("Jack".to_string())], jack_is_a_dog);
    /// #     Ok(())
    /// # }
    /// ```
    fn is<T>(self, other: T) -> dsl::Is<Self, T>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Grouped(Is::new(self, other.as_expression()))
    }

    /// Creates a Sqlite `IS NOT` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// let jack_is_not_a_spider = animals
    ///     .select(name)
    ///     .filter(species.is_not("spider"))
    ///     .get_results::<Option<String>>(&connection)?;
    /// assert_eq!(vec![Some("Jack".to_string())], jack_is_not_a_spider);
    /// #     Ok(())
    /// # }
    /// ```
    fn is_not<T>(self, other: T) -> dsl::IsNot<Self, T>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Grouped(IsNot::new(self, other.as_expression()))
    }
}

impl<T: Expression> SqliteExpressionMethods for T {}
<commit_msg>Description behaves in doc<commit_after>//! Sqlite specific expression methods.

use super::operators::*;
use crate::dsl;
use crate::expression::grouped::Grouped;
use crate::expression::{AsExpression, Expression};
use crate::sql_types::SqlType;

/// Sqlite specific methods which are present on all expressions.
pub trait SqliteExpressionMethods: Expression + Sized {
    /// Creates a Sqlite `IS` expression.
    ///
    /// The `IS` operator work like = except when one or both of the operands are NULL.
    /// In this case, if both operands are NULL, then the `IS` operator evaluates to true.
    /// If one operand is NULL and the other is not, then the `IS` operator evaluates to false.
    /// It is not possible for an `IS` expression to evaluate to NULL.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// let jack_is_a_dog = animals
    ///     .select(name)
    ///     .filter(species.is("dog"))
    ///     .get_results::<Option<String>>(&connection)?;
    /// assert_eq!(vec![Some("Jack".to_string())], jack_is_a_dog);
    /// #     Ok(())
    /// # }
    /// ```
    fn is<T>(self, other: T) -> dsl::Is<Self, T>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Grouped(Is::new(self, other.as_expression()))
    }

    /// Creates a Sqlite `IS NOT` expression.
    ///
    /// The `IS NOT` operator work like != except when one or both of the operands are NULL.
    /// In this case, if both operands are NULL, then the `IS NOT` operator evaluates to false.
    /// If one operand is NULL and the other is not, then the `IS NOT` operator is true.
    /// It is not possible for an `IS NOT` expression to evaluate to NULL.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// let jack_is_not_a_spider = animals
    ///     .select(name)
    ///     .filter(species.is_not("spider"))
    ///     .get_results::<Option<String>>(&connection)?;
    /// assert_eq!(vec![Some("Jack".to_string())], jack_is_not_a_spider);
    /// #     Ok(())
    /// # }
    /// ```
    fn is_not<T>(self, other: T) -> dsl::IsNot<Self, T>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Grouped(IsNot::new(self, other.as_expression()))
    }
}

impl<T: Expression> SqliteExpressionMethods for T {}
<|endoftext|>


<commit_before>use std::net::IpAddr;
use std::sync::{Arc, Mutex};
use std::os::unix::io::{AsRawFd, RawFd};

use {amy, c_ares};

use tracker::{ErrorKind, Result, ResultExt};
use util::FHashMap;

#[derive(Debug)]
pub struct QueryResponse {
    pub id: usize,
    pub res: Result<IpAddr>,
}

pub struct Resolver {
    reg: amy::Registrar,
    socks: FHashMap<usize, c_ares::Socket>,
    chan: c_ares::Channel,
    sender: Arc<Mutex<amy::Sender<QueryResponse>>>,
}

struct CSockWrapper(c_ares::Socket);

impl AsRawFd for CSockWrapper {
    fn as_raw_fd(&self) -> RawFd {
        self.0
    }
}

impl Resolver {
    pub fn new(reg: amy::Registrar, send: amy::Sender<QueryResponse>) -> Resolver {
        let mut opts = c_ares::Options::new();
        opts.set_timeout(3000).set_tries(4);
        Resolver {
            reg,
            socks: FHashMap::default(),
            chan: c_ares::Channel::with_options(opts).unwrap(),
            sender: Arc::new(Mutex::new(send)),
        }
    }

    pub fn contains(&self, id: usize) -> bool {
        self.socks.contains_key(&id)
    }

    pub fn readable(&mut self, id: usize) {
        self.chan.process_fd(self.socks[&id], c_ares::SOCKET_BAD);
    }

    pub fn writable(&mut self, id: usize) {
        self.chan.process_fd(c_ares::SOCKET_BAD, self.socks[&id]);
    }

    pub fn tick(&mut self) {
        // Add any unrecognized fd's to amy for polling, remove
        // any fd's in amy which are no longer handled by c_ares
        self.socks = self.chan
            .get_sock()
            .iter()
            .map(|(fd, _, _)| {
                (
                    self.reg
                        .register(&CSockWrapper(fd), amy::Event::Both)
                        .unwrap(),
                    fd,
                )
            })
            .collect();
    }

    pub fn new_query(&mut self, id: usize, host: &str) {
        // TODO: handle ipv6 too
        let s = self.sender.clone();
        self.chan
            .get_host_by_name(host, c_ares::AddressFamily::INET, move |res| {
                let res = res.chain_err(|| ErrorKind::DNS)
                    .and_then(|ips| ips.addresses().next().ok_or_else(|| ErrorKind::DNS.into()));
                let resp = QueryResponse { id, res };
                if s.lock().unwrap().send(resp).is_err() {
                    // Other end was shutdown, ignore
                }
            });
    }
}
<commit_msg>Revert dns alterations<commit_after>use std::collections::HashSet;
use std::net::IpAddr;
use std::sync::{Arc, Mutex};
use std::os::unix::io::{AsRawFd, RawFd};

use {amy, c_ares};

use tracker::{ErrorKind, Result, ResultExt};
use util::FHashMap;

#[derive(Debug)]
pub struct QueryResponse {
    pub id: usize,
    pub res: Result<IpAddr>,
}

pub struct Resolver {
    reg: amy::Registrar,
    socks: FHashMap<usize, c_ares::Socket>,
    csocks: FHashMap<c_ares::Socket, usize>,
    chan: c_ares::Channel,
    sender: Arc<Mutex<amy::Sender<QueryResponse>>>,
    marked: HashSet<usize>,
}

struct CSockWrapper(c_ares::Socket);

impl AsRawFd for CSockWrapper {
    fn as_raw_fd(&self) -> RawFd {
        self.0
    }
}

impl Resolver {
    pub fn new(reg: amy::Registrar, send: amy::Sender<QueryResponse>) -> Resolver {
        let mut opts = c_ares::Options::new();
        opts.set_timeout(3000).set_tries(4);
        Resolver {
            reg,
            socks: FHashMap::default(),
            csocks: FHashMap::default(),
            chan: c_ares::Channel::with_options(opts).unwrap(),
            sender: Arc::new(Mutex::new(send)),
            marked: HashSet::new(),
        }
    }

    pub fn contains(&self, id: usize) -> bool {
        self.socks.contains_key(&id)
    }

    pub fn readable(&mut self, id: usize) {
        self.chan.process_fd(self.socks[&id], c_ares::SOCKET_BAD);
    }

    pub fn writable(&mut self, id: usize) {
        self.chan.process_fd(c_ares::SOCKET_BAD, self.socks[&id]);
    }

    pub fn tick(&mut self) {
        self.marked.clear();
        // Add any unrecognized fd's to amy for polling, remove
        // any fd's in amy which are no longer handled by c_ares
        for (fd, _, _) in &self.chan.get_sock() {
            // Not efficient, but the max number of queries active at at time is likely limited
            if let Some(id) = self.csocks.get(&fd).cloned() {
                self.marked.insert(id);
            } else {
                let id = self.reg
                    .register(&CSockWrapper(fd), amy::Event::Both)
                    .unwrap();
                self.marked.insert(id);
                self.socks.insert(id, fd);
                self.csocks.insert(fd, id);
            }
        }

        // Any socks remaining in csocks should be deregistered and destroyed
        let socks = &mut self.socks;
        let csocks = &mut self.csocks;
        let marked = &self.marked;
        let reg = &self.reg;
        socks.retain(|id, fd| {
            if marked.contains(id) {
                true
            } else {
                csocks.remove(fd);
                reg.deregister(&CSockWrapper(*fd)).ok();
                false
            }
        });
    }

    pub fn new_query(&mut self, id: usize, host: &str) {
        // TODO: handle ipv6 too
        let s = self.sender.clone();
        self.chan
            .get_host_by_name(host, c_ares::AddressFamily::INET, move |res| {
                let res = res.chain_err(|| ErrorKind::DNS)
                    .and_then(|ips| ips.addresses().next().ok_or_else(|| ErrorKind::DNS.into()));
                let resp = QueryResponse { id, res };
                if s.lock().unwrap().send(resp).is_err() {
                    // Other end was shutdown, ignore
                }
            });
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
extern crate hyper;

#[macro_use]
extern crate serde_derive;

use std::process::{Command};
use std::io::Read;
use hyper::header::ContentType;
use hyper::client::Client;
use serde_json::Value;

#[derive(Serialize, Deserialize)]
struct RPCRequest {
    jsonrpc: String,
    method: String,
    params: Vec<String>,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCObjectRequest<T> {
    jsonrpc: String,
    method: String,
    params: T,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCObjectResponse<T> {
    jsonrpc: String,
    result: T,
    id: usize,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransaction {
    pub hash: String,
    pub nonce: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub transactionIndex: String,
    pub from: String,
    pub to: String,
    pub value: String,
    pub gas: String,
    pub gasPrice: String,
    pub input: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCBlock {
    pub number: String,
    pub hash: String,
    pub parentHash: String,
    pub nonce: String,
    pub sha3Uncles: String,
    pub logsBloom: String,
    pub transactionsRoot: String,
    pub stateRoot: String,
    pub miner: String,
    pub difficulty: String,
    pub totalDifficulty: String,
    pub extraData: String,
    pub size: String,
    pub gasLimit: String,
    pub gasUsed: String,
    pub timestamp: String,
    pub transactions: Vec<String>,
    pub uncles: Vec<String>
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum RPCSyncStatus {
    NotSync(bool),
    Sync {
        startingBlock: String,
        currentBlock: String,
        highestBlock: String,
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransactionReceipt {
    pub transactionHash: String,
    pub transactionIndex: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub cumulativeGasUsed: String,
    pub gasUsed: String,
    pub contractAddress: String,
    pub logs: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCFilter {
    pub fromBlock: String,
    pub toBlock: String,
    pub address: String,
    pub topics: Vec<String>,
}

pub struct GethRPCClient {
    endpoint: String,
    free_id: usize,
}

impl GethRPCClient {
    pub fn new(endpoint: &str) -> Self {
        GethRPCClient {
            endpoint: endpoint.to_string(),
            free_id: 1,
        }
    }

    fn rpc_request<T: serde::Deserialize>(&mut self, method: &str, params: Vec<String>) -> T {
        self.rpc_object_request::<Vec<String>, T>(method, params)
    }

    fn rpc_object_request<Req: serde::Serialize, Res: serde::Deserialize>(&mut self, method: &str, params: Req) -> Res {
        let request = RPCObjectRequest {
            jsonrpc: "2.0".to_string(),
            method: method.to_string(),
            params: params,
            id: self.free_id,
        };
        self.free_id = self.free_id + 1;

        let client = Client::new();
        let mut response_raw = client.post(&self.endpoint)
            .header(ContentType::json())
            .body(&serde_json::to_string(&request).unwrap())
            .send().unwrap();
        let mut buffer = String::new();
        response_raw.read_to_string(&mut buffer).unwrap();

        let response: RPCObjectResponse<Res> = serde_json::from_str(&buffer).unwrap();
        response.result
    }

    pub fn client_version(&mut self) -> String {
        self.rpc_request::<String>("web3_clientVersion", vec![])
    }

    pub fn net_version(&mut self) -> String {
        self.rpc_request::<String>("net_version", vec![])
    }

    pub fn net_listening(&mut self) -> bool {
        self.rpc_request::<bool>("net_listening", vec![])
    }

    pub fn net_peer_count(&mut self) -> String {
        self.rpc_request::<String>("net_peerCount", vec![])
    }

    pub fn sha3(&mut self, data: &str) -> String {
        self.rpc_request::<String>("web3_sha3", vec![])
    }

    pub fn protocol_version(&mut self) -> String {
        self.rpc_request::<String>("eth_protocolVersion", vec![])
    }

    pub fn syncing(&mut self) -> RPCSyncStatus {
        self.rpc_request::<RPCSyncStatus>("eth_syncing", vec![])
    }

    pub fn coinbase(&mut self) -> String {
        self.rpc_request::<String>("eth_coinbase", vec![])
    }

    pub fn mining(&mut self) -> bool {
        self.rpc_request::<bool>("eth_mining", vec![])
    }

    pub fn hashrate(&mut self) -> String {
        self.rpc_request::<String>("eth_hashrate", vec![])
    }

    pub fn gas_price(&mut self) -> String {
        self.rpc_request::<String>("eth_gasPrice", vec![])
    }

    pub fn accounts(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_accounts", vec![])
    }

    pub fn block_number(&mut self) -> String {
        self.rpc_request::<String>("eth_blockNumber", vec![])
    }

    pub fn get_balance(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getBalance",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_storage_at(&mut self, address: &str, index: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getStorageAt",
                                   vec![address.to_string(), index.to_string(), number.to_string()])
    }

    pub fn get_transaction_count(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getTransactionCount",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_block_transaction_count_by_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByHash",
                                   vec![hash.to_string()])
    }

    pub fn get_block_transaction_count_by_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByNumber",
                                   vec![number.to_string()])
    }

    pub fn get_uncle_count_by_block_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockHash",
                                   vec![hash.to_string()])
    }

    pub fn get_uncle_count_by_block_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockNumber",
                                   vec![number.to_string()])
    }

    pub fn get_code(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getCode", vec![address.to_string(), number.to_string()])
    }

    pub fn sign(&mut self, address: &str, message: &str) -> String {
        self.rpc_request::<String>("eth_sign", vec![address.to_string(), message.to_string()])
    }

    pub fn send_transaction(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn send_raw_transaction(&mut self, data: &str) -> String {
        self.rpc_request::<String>("eth_sendRawTransaction", vec![data.to_string()])
    }

    pub fn call(&mut self, transaction: RPCTransaction) -> String {
        self.rpc_object_request::<[RPCTransaction; 1], String>("eth_call", [transaction])
    }

    pub fn estimate_gas(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn get_block_by_hash(&mut self, hash: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByHash",
                                     vec![hash.to_string(), "false".to_string()])
    }

    pub fn get_block_by_number(&mut self, number: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByNumber",
                                     vec![number.to_string(), "false".to_string()])
    }

    pub fn get_transaction_by_hash(&mut self, hash: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByHash",
                                           vec![hash.to_string()])
    }

    pub fn get_transaction_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockHashAndIndex",
                                           vec![hash.to_string(), index.to_string()])
    }

    pub fn get_transaction_by_block_number_and_index(&mut self, number: &str, index: &str)
                                                 -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockNumberAndIndex",
                                           vec![number.to_string(), index.to_string()])
    }

    pub fn get_transaction_receipt(&mut self, hash: &str) -> RPCTransactionReceipt {
        self.rpc_request::<RPCTransactionReceipt>("eth_getTransactionReceipt",
                                                 vec![hash.to_string()])
    }

    pub fn get_uncle_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockHashAndIndex",
                                     vec![hash.to_string(), index.to_string()])
    }

    pub fn get_uncle_by_block_number_and_index(&mut self, number: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockNumberAndIndex",
                                     vec![number.to_string(), index.to_string()])
    }

    pub fn get_compilers(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getCompilers", vec![])
    }

    pub fn compile_solidity(&mut self, source: &str) -> String {
        unimplemented!()
    }

    pub fn compile_lll(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileLLL", vec![source.to_string()])
    }

    pub fn compile_serpent(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileSerpent", vec![source.to_string()])
    }

    pub fn new_filter(&mut self, filter: RPCFilter) -> String {
        unimplemented!()
    }

    pub fn new_block_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newBlockFilter", vec![])
    }

    pub fn new_pending_transaction_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newPendingTransactionFilter", vec![])
    }

    pub fn uninstall_filter(&mut self, id: &str) -> bool {
        self.rpc_request::<bool>("eth_uninstallFilter", vec![id.to_string()])
    }

    pub fn get_filter_changes(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_filter_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_work(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getWork", vec![])
    }

    pub fn submit_work(&mut self, nonce: &str, pow: &str, mix: &str) -> bool {
        self.rpc_request::<bool>("eth_submitWork",
                                 vec![nonce.to_string(), pow.to_string(), mix.to_string()])
    }

    pub fn submit_hashrate(&mut self, hashrate: &str, id: &str) -> bool {
        self.rpc_request::<bool>("eth_submitHashrate",
                                 vec![hashrate.to_string(), id.to_string()])
    }

    pub fn put_string(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putString",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_string(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getString",
                                   vec![db.to_string(), key.to_string()])
    }

    pub fn put_hex(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putHex",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_hex(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getHex",
                                   vec![db.to_string(), key.to_string()])
    }
}

pub fn regression(address: &str) -> bool {
    let mut client = GethRPCClient::new("http://localhost:8545");
    let height = usize::from_str_radix(&client.block_number(), 16).unwrap();
    println!("height: {}", height);

    for blk_no in 49439..height {
        let block = client.get_block_by_number(format!("0x{:x}", blk_no).as_str());
        println!("{:?}", block);
    }
    false
}
<commit_msg>Problem: eth_call RPC missing block number<commit_after>extern crate serde;
extern crate serde_json;
extern crate hyper;

#[macro_use]
extern crate serde_derive;

use std::process::{Command};
use std::io::Read;
use hyper::header::ContentType;
use hyper::client::Client;
use serde_json::Value;

#[derive(Serialize, Deserialize)]
struct RPCRequest {
    jsonrpc: String,
    method: String,
    params: Vec<String>,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCObjectRequest<T> {
    jsonrpc: String,
    method: String,
    params: T,
    id: usize,
}

#[derive(Serialize, Deserialize)]
struct RPCObjectResponse<T> {
    jsonrpc: String,
    result: T,
    id: usize,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransaction {
    pub hash: String,
    pub nonce: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub transactionIndex: String,
    pub from: String,
    pub to: String,
    pub value: String,
    pub gas: String,
    pub gasPrice: String,
    pub input: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCCall {
    pub from: String,
    pub to: String,
    pub gas: String,
    pub gasPrice: String,
    pub value: String,
    pub data: String,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCBlock {
    pub number: String,
    pub hash: String,
    pub parentHash: String,
    pub nonce: String,
    pub sha3Uncles: String,
    pub logsBloom: String,
    pub transactionsRoot: String,
    pub stateRoot: String,
    pub miner: String,
    pub difficulty: String,
    pub totalDifficulty: String,
    pub extraData: String,
    pub size: String,
    pub gasLimit: String,
    pub gasUsed: String,
    pub timestamp: String,
    pub transactions: Vec<String>,
    pub uncles: Vec<String>
}

#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum RPCSyncStatus {
    NotSync(bool),
    Sync {
        startingBlock: String,
        currentBlock: String,
        highestBlock: String,
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCTransactionReceipt {
    pub transactionHash: String,
    pub transactionIndex: String,
    pub blockHash: String,
    pub blockNumber: String,
    pub cumulativeGasUsed: String,
    pub gasUsed: String,
    pub contractAddress: String,
    pub logs: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct RPCFilter {
    pub fromBlock: String,
    pub toBlock: String,
    pub address: String,
    pub topics: Vec<String>,
}

pub struct GethRPCClient {
    endpoint: String,
    free_id: usize,
}

impl GethRPCClient {
    pub fn new(endpoint: &str) -> Self {
        GethRPCClient {
            endpoint: endpoint.to_string(),
            free_id: 1,
        }
    }

    fn rpc_request<T: serde::Deserialize>(&mut self, method: &str, params: Vec<String>) -> T {
        self.rpc_object_request::<Vec<String>, T>(method, params)
    }

    fn rpc_object_request<Req: serde::Serialize, Res: serde::Deserialize>(&mut self, method: &str, params: Req) -> Res {
        let request = RPCObjectRequest {
            jsonrpc: "2.0".to_string(),
            method: method.to_string(),
            params: params,
            id: self.free_id,
        };
        self.free_id = self.free_id + 1;

        let client = Client::new();
        let mut response_raw = client.post(&self.endpoint)
            .header(ContentType::json())
            .body(&serde_json::to_string(&request).unwrap())
            .send().unwrap();
        let mut buffer = String::new();
        response_raw.read_to_string(&mut buffer).unwrap();

        let response: RPCObjectResponse<Res> = serde_json::from_str(&buffer).unwrap();
        response.result
    }

    pub fn client_version(&mut self) -> String {
        self.rpc_request::<String>("web3_clientVersion", vec![])
    }

    pub fn net_version(&mut self) -> String {
        self.rpc_request::<String>("net_version", vec![])
    }

    pub fn net_listening(&mut self) -> bool {
        self.rpc_request::<bool>("net_listening", vec![])
    }

    pub fn net_peer_count(&mut self) -> String {
        self.rpc_request::<String>("net_peerCount", vec![])
    }

    pub fn sha3(&mut self, data: &str) -> String {
        self.rpc_request::<String>("web3_sha3", vec![])
    }

    pub fn protocol_version(&mut self) -> String {
        self.rpc_request::<String>("eth_protocolVersion", vec![])
    }

    pub fn syncing(&mut self) -> RPCSyncStatus {
        self.rpc_request::<RPCSyncStatus>("eth_syncing", vec![])
    }

    pub fn coinbase(&mut self) -> String {
        self.rpc_request::<String>("eth_coinbase", vec![])
    }

    pub fn mining(&mut self) -> bool {
        self.rpc_request::<bool>("eth_mining", vec![])
    }

    pub fn hashrate(&mut self) -> String {
        self.rpc_request::<String>("eth_hashrate", vec![])
    }

    pub fn gas_price(&mut self) -> String {
        self.rpc_request::<String>("eth_gasPrice", vec![])
    }

    pub fn accounts(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_accounts", vec![])
    }

    pub fn block_number(&mut self) -> String {
        self.rpc_request::<String>("eth_blockNumber", vec![])
    }

    pub fn get_balance(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getBalance",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_storage_at(&mut self, address: &str, index: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getStorageAt",
                                   vec![address.to_string(), index.to_string(), number.to_string()])
    }

    pub fn get_transaction_count(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getTransactionCount",
                                   vec![address.to_string(), number.to_string()])
    }

    pub fn get_block_transaction_count_by_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByHash",
                                   vec![hash.to_string()])
    }

    pub fn get_block_transaction_count_by_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getBlockTransactionCountByNumber",
                                   vec![number.to_string()])
    }

    pub fn get_uncle_count_by_block_hash(&mut self, hash: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockHash",
                                   vec![hash.to_string()])
    }

    pub fn get_uncle_count_by_block_number(&mut self, number: &str) -> String {
        self.rpc_request::<String>("eth_getUncleCountByBlockNumber",
                                   vec![number.to_string()])
    }

    pub fn get_code(&mut self, address: &str, number: &str) -> String {
        self.rpc_request::<String>("eth_getCode", vec![address.to_string(), number.to_string()])
    }

    pub fn sign(&mut self, address: &str, message: &str) -> String {
        self.rpc_request::<String>("eth_sign", vec![address.to_string(), message.to_string()])
    }

    pub fn send_transaction(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn send_raw_transaction(&mut self, data: &str) -> String {
        self.rpc_request::<String>("eth_sendRawTransaction", vec![data.to_string()])
    }

    pub fn call(&mut self, transaction: RPCCall, number: &str) -> String {
        self.rpc_object_request::<(RPCCall, String), String>("eth_call", (transaction, number.to_string()))
    }

    pub fn estimate_gas(&mut self, transaction: RPCTransaction) -> String {
        unimplemented!()
    }

    pub fn get_block_by_hash(&mut self, hash: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByHash",
                                     vec![hash.to_string(), "false".to_string()])
    }

    pub fn get_block_by_number(&mut self, number: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getBlockByNumber",
                                     vec![number.to_string(), "false".to_string()])
    }

    pub fn get_transaction_by_hash(&mut self, hash: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByHash",
                                           vec![hash.to_string()])
    }

    pub fn get_transaction_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockHashAndIndex",
                                           vec![hash.to_string(), index.to_string()])
    }

    pub fn get_transaction_by_block_number_and_index(&mut self, number: &str, index: &str)
                                                 -> RPCTransaction {
        self.rpc_request::<RPCTransaction>("eth_getTransactionByBlockNumberAndIndex",
                                           vec![number.to_string(), index.to_string()])
    }

    pub fn get_transaction_receipt(&mut self, hash: &str) -> RPCTransactionReceipt {
        self.rpc_request::<RPCTransactionReceipt>("eth_getTransactionReceipt",
                                                 vec![hash.to_string()])
    }

    pub fn get_uncle_by_block_hash_and_index(&mut self, hash: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockHashAndIndex",
                                     vec![hash.to_string(), index.to_string()])
    }

    pub fn get_uncle_by_block_number_and_index(&mut self, number: &str, index: &str) -> RPCBlock {
        self.rpc_request::<RPCBlock>("eth_getUncleByBlockNumberAndIndex",
                                     vec![number.to_string(), index.to_string()])
    }

    pub fn get_compilers(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getCompilers", vec![])
    }

    pub fn compile_solidity(&mut self, source: &str) -> String {
        unimplemented!()
    }

    pub fn compile_lll(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileLLL", vec![source.to_string()])
    }

    pub fn compile_serpent(&mut self, source: &str) -> String {
        self.rpc_request::<String>("eth_compileSerpent", vec![source.to_string()])
    }

    pub fn new_filter(&mut self, filter: RPCFilter) -> String {
        unimplemented!()
    }

    pub fn new_block_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newBlockFilter", vec![])
    }

    pub fn new_pending_transaction_filter(&mut self) -> String {
        self.rpc_request::<String>("eth_newPendingTransactionFilter", vec![])
    }

    pub fn uninstall_filter(&mut self, id: &str) -> bool {
        self.rpc_request::<bool>("eth_uninstallFilter", vec![id.to_string()])
    }

    pub fn get_filter_changes(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_filter_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_logs(&mut self, id: &str) -> String {
        unimplemented!()
    }

    pub fn get_work(&mut self) -> Vec<String> {
        self.rpc_request::<Vec<String>>("eth_getWork", vec![])
    }

    pub fn submit_work(&mut self, nonce: &str, pow: &str, mix: &str) -> bool {
        self.rpc_request::<bool>("eth_submitWork",
                                 vec![nonce.to_string(), pow.to_string(), mix.to_string()])
    }

    pub fn submit_hashrate(&mut self, hashrate: &str, id: &str) -> bool {
        self.rpc_request::<bool>("eth_submitHashrate",
                                 vec![hashrate.to_string(), id.to_string()])
    }

    pub fn put_string(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putString",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_string(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getString",
                                   vec![db.to_string(), key.to_string()])
    }

    pub fn put_hex(&mut self, db: &str, key: &str, value: &str) -> bool {
        self.rpc_request::<bool>("db_putHex",
                                 vec![db.to_string(), key.to_string(), value.to_string()])
    }

    pub fn get_hex(&mut self, db: &str, key: &str) -> String {
        self.rpc_request::<String>("db_getHex",
                                   vec![db.to_string(), key.to_string()])
    }
}

pub fn regression(address: &str) -> bool {
    let mut client = GethRPCClient::new("http://localhost:8545");
    let height = usize::from_str_radix(&client.block_number(), 16).unwrap();
    println!("height: {}", height);

    for blk_no in 49439..height {
        let block = client.get_block_by_number(format!("0x{:x}", blk_no).as_str());
        println!("{:?}", block);
    }
    false
}
<|endoftext|>


<commit_before>use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;
use std::thread;

use platform::time::sleep_secs;
use protocol::cmd::Cmd;
use protocol::cmd::Get;
use protocol::cmd::Resp;
use protocol::cmd::Value;

type CmdSender = Sender<Cmd>;
type CmdReceiver = Receiver<Cmd>;

type RespSender = Sender<Resp>;
type RespReceiver = Receiver<Resp>;

fn transport(id: u64, sender: CmdSender, receiver: RespReceiver) {
    for i in 0..5 {
        let val = Cmd::Get(Get::new("x"));
        println!("[transport {}] Sending: {:?}", id, val.clone());
        sender.send(val.clone()).unwrap();
        println!("[transport {}] Sent: {:?}", id, val.clone());

        println!("[transport {}] Receiving...", id);
        let val = receiver.recv().unwrap();
        println!("[transport {}] Received: {:?}", id, val);

        sleep_secs(1.0);
    }

    println!("[transport {}] Stopping", id);
}

fn driver(sender: RespSender, receiver: CmdReceiver) {
    loop {
        println!("[driver]      Receiving...");
        let val = receiver.recv().unwrap();
        println!("[driver]      Received: {:?}", val);

        let val = Resp::Value(Value::new("x", vec![1, 2, 3]));
        println!("[driver]      Sending: {:?}", val.clone());
        sender.send(val.clone()).unwrap();
        println!("[driver]      Sent: {:?}", val.clone());
    }

    println!("[driver]      Stopping");
}

pub fn run_it() {
    let (c_tx, c_rx) = mpsc::channel();
    let (r_tx, r_rx) = mpsc::channel();

    println!("[listen]      Launching driver");
    thread::spawn(move || {
        driver(r_tx, c_rx);
    });

    println!("[listen]      Launching transport {}", 1);
    thread::spawn(move || {
        transport(1, c_tx, r_rx);
    });

    loop {
        sleep_secs(1.0);
    }
}
<commit_msg>working demo with driver and two transports and correct multiplexing<commit_after>use std::sync::mpsc::Sender;
use std::sync::mpsc::Receiver;
use std::sync::mpsc;
use std::thread;

use platform::time::sleep_secs;
use protocol::cmd::Cmd;
use protocol::cmd::Get;
use protocol::cmd::Resp;
use protocol::cmd::Value;

type CmdSender = Sender<(u64, Cmd)>;
type CmdReceiver = Receiver<(u64, Cmd)>;

type RespSender = Sender<Resp>;
type RespReceiver = Receiver<Resp>;

fn transport(id: u64, sender: CmdSender, receiver: RespReceiver) {
    for i in 0..5 {
        let key = format!("x{}", id);
        let val = Cmd::Get(Get { key: key });
        println!("[transport {}] Sending: {:?}", id, val.clone());
        sender.send((id, val.clone())).unwrap();
        println!("[transport {}] Sent: {:?}", id, val.clone());

        println!("[transport {}] Receiving...", id);
        let val = receiver.recv().unwrap();
        println!("[transport {}] Received: {:?}", id, val);

        sleep_secs(1.0);
    }

    println!("[transport {}] Stopping", id);
}

fn driver(receiver: CmdReceiver, sender1: RespSender, sender2: RespSender) {
    loop {
        println!("[driver]      Receiving...");
        let (id, cmd) = receiver.recv().unwrap();
        println!("[driver]      Received: {:?}", cmd);

        let mut key = "?".to_string();
        match cmd {
            Cmd::Get(get) => { key = get.key; },
            _ => (),
        }

        let val = Resp::Value(Value { key: key, data: vec![1, 2, 3] });
        println!("[driver]      Sending: {:?}", val.clone());
        match id {
            1 => {
                sender1.send(val.clone()).unwrap();
            },
            2 => {
                sender2.send(val.clone()).unwrap();
            },
            _ => (),
        }
        println!("[driver]      Sent: {:?}", val.clone());
    }

    println!("[driver]      Stopping");
}

pub fn run_it() {
    let (c_tx, c_rx) = mpsc::channel();
    let c_tx2 = c_tx.clone();

    let (r_tx1, r_rx1) = mpsc::channel();
    let (r_tx2, r_rx2) = mpsc::channel();

    println!("[listen]      Launching driver");
    thread::spawn(move || {
        driver(c_rx, r_tx1, r_tx2);
    });

    println!("[listen]      Launching transport {}", 1);
    thread::spawn(move || {
        transport(1, c_tx, r_rx1);
    });

    println!("[listen]      Launching transport {}", 2);
    thread::spawn(move || {
        transport(2, c_tx2, r_rx2);
    });

    loop {
        sleep_secs(1.0);
    }
}
<|endoftext|>