<commit_before>#![warn(clippy::all, rust_2018_idioms)]

use chrono::prelude::Utc;
use hmac::{Hmac, Mac, NewMac};
use reqwest::{
    blocking::{Body, Client, Response},
    header,
};
use sha1::Sha1;

pub use reqwest::Error;

#[derive(Clone, Debug)]
pub struct Bucket {
    name: String,
    region: Option<String>,
    access_key: String,
    secret_key: String,
    proto: String,
}

impl Bucket {
    pub fn new(
        name: String,
        region: Option<String>,
        access_key: String,
        secret_key: String,
        proto: &str,
    ) -> Bucket {
        Bucket {
            name,
            region,
            access_key,
            secret_key,
            proto: proto.to_string(),
        }
    }

    pub fn put<R: std::io::Read + Send + 'static>(
        &self,
        client: &Client,
        path: &str,
        content: R,
        content_length: u64,
        content_type: &str,
        extra_headers: header::HeaderMap,
    ) -> Result<Response, Error> {
        let path = path.strip_prefix("/").unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("PUT", &date, path, "", content_type);
        let url = self.url(path);

        client
            .put(&url)
            .header(header::AUTHORIZATION, auth)
            .header(header::CONTENT_TYPE, content_type)
            .header(header::DATE, date)
            .header(header::USER_AGENT, "crates.io (https://crates.io)")
            .headers(extra_headers)
            .body(Body::sized(content, content_length))
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn delete(&self, client: &Client, path: &str) -> Result<Response, Error> {
        let path = path.strip_prefix("/").unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("DELETE", &date, path, "", "");
        let url = self.url(path);

        client
            .delete(&url)
            .header(header::DATE, date)
            .header(header::AUTHORIZATION, auth)
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn host(&self) -> String {
        format!(
            "{}.s3{}.amazonaws.com",
            self.name,
            match self.region {
                Some(ref r) if !r.is_empty() => format!("-{}", r),
                Some(_) => String::new(),
                None => String::new(),
            }
        )
    }

    fn auth(&self, verb: &str, date: &str, path: &str, md5: &str, content_type: &str) -> String {
        let string = format!(
            "{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
            verb = verb,
            md5 = md5,
            ty = content_type,
            date = date,
            headers = "",
            resource = format!("/{}/{}", self.name, path)
        );
        let signature = {
            let key = self.secret_key.as_bytes();
            let mut h = Hmac::<Sha1>::new_varkey(key).expect("HMAC can take key of any size");
            h.update(string.as_bytes());
            let res = h.finalize().into_bytes();
            base64::encode(&res)
        };
        format!("AWS {}:{}", self.access_key, signature)
    }

    fn url(&self, path: &str) -> String {
        format!("{}://{}/{}", self.proto, self.host(), path)
    }
}
<commit_msg>s3: Increase `put()` timeout to 60sec<commit_after>#![warn(clippy::all, rust_2018_idioms)]

use chrono::prelude::Utc;
use hmac::{Hmac, Mac, NewMac};
use reqwest::{
    blocking::{Body, Client, Response},
    header,
};
use sha1::Sha1;
use std::time::Duration;

pub use reqwest::Error;

#[derive(Clone, Debug)]
pub struct Bucket {
    name: String,
    region: Option<String>,
    access_key: String,
    secret_key: String,
    proto: String,
}

impl Bucket {
    pub fn new(
        name: String,
        region: Option<String>,
        access_key: String,
        secret_key: String,
        proto: &str,
    ) -> Bucket {
        Bucket {
            name,
            region,
            access_key,
            secret_key,
            proto: proto.to_string(),
        }
    }

    pub fn put<R: std::io::Read + Send + 'static>(
        &self,
        client: &Client,
        path: &str,
        content: R,
        content_length: u64,
        content_type: &str,
        extra_headers: header::HeaderMap,
    ) -> Result<Response, Error> {
        let path = path.strip_prefix("/").unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("PUT", &date, path, "", content_type);
        let url = self.url(path);

        client
            .put(&url)
            .header(header::AUTHORIZATION, auth)
            .header(header::CONTENT_TYPE, content_type)
            .header(header::DATE, date)
            .header(header::USER_AGENT, "crates.io (https://crates.io)")
            .headers(extra_headers)
            .body(Body::sized(content, content_length))
            .timeout(Duration::from_secs(60))
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn delete(&self, client: &Client, path: &str) -> Result<Response, Error> {
        let path = path.strip_prefix("/").unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("DELETE", &date, path, "", "");
        let url = self.url(path);

        client
            .delete(&url)
            .header(header::DATE, date)
            .header(header::AUTHORIZATION, auth)
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn host(&self) -> String {
        format!(
            "{}.s3{}.amazonaws.com",
            self.name,
            match self.region {
                Some(ref r) if !r.is_empty() => format!("-{}", r),
                Some(_) => String::new(),
                None => String::new(),
            }
        )
    }

    fn auth(&self, verb: &str, date: &str, path: &str, md5: &str, content_type: &str) -> String {
        let string = format!(
            "{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
            verb = verb,
            md5 = md5,
            ty = content_type,
            date = date,
            headers = "",
            resource = format!("/{}/{}", self.name, path)
        );
        let signature = {
            let key = self.secret_key.as_bytes();
            let mut h = Hmac::<Sha1>::new_varkey(key).expect("HMAC can take key of any size");
            h.update(string.as_bytes());
            let res = h.finalize().into_bytes();
            base64::encode(&res)
        };
        format!("AWS {}:{}", self.access_key, signature)
    }

    fn url(&self, path: &str) -> String {
        format!("{}://{}/{}", self.proto, self.host(), path)
    }
}
<|endoftext|>


<commit_before>use glium::VertexBuffer;
use glium::IndexBuffer;
use glium::Program;
use glium::DrawParameters;
use glium::Surface;
use glium::Frame;
use glium::Rect;
use glium::Texture2d;
use glium::Blend;
use glium::index::PrimitiveType;
use glium::backend::Facade;

use nalgebra::Mat4;
use nalgebra::OrthoMat3;

use mem::MemSection;
use mem::AddressSpace;

pub const LCD_WIDTH: u32    = 160;
pub const LCD_HEIGHT: u32   = 144;
pub const LCD_ASPECT: f32   = (LCD_WIDTH as f32) / (LCD_HEIGHT as f32);

pub const BG_SIZE: u32      = 256;

/// Period of the V-Blank in ns. V-Blank frequency is ~59.7 Hz
pub const VBLANK_PERIOD: u64 = 16_750_419;

/// Period of the H-Blank in ns. H-Blank frequency is ~9198 Hz
pub const HBLANK_PERIOD: u64 = 108_719;

static SIMPLE_VERT: &'static str = r#"
#version 140

in vec2 coord;

out vec2 tex_coord;

uniform mat4 projection;
uniform vec2 translate;

void main() {
    tex_coord = coord;
    gl_Position = projection * vec4(coord.x + translate.x, coord.y + translate.y, 0.0, 1.0);
}
"#;

static COLOR_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform vec4 color;
uniform vec2 translate;

void main() {
    frag_color = color;
}
"#;

static TEXTURE_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform sampler2D tex;

void main() {
    frag_color = texture(tex, tex_coord);
}
"#;

#[derive(Copy, Clone)]
struct Vertex {
    coord: [f32; 2],
}

implement_vertex!(Vertex, coord);

pub struct GbDisplay {
    simple_surface: VertexBuffer<Vertex>,
    simple_surface_idx: IndexBuffer<u32>,
    color_prog: Program,
    tex_prog: Program,
    projection: Mat4<f32>,
    ly_counter: u8,
}

impl GbDisplay {

    pub fn new<F>(display: &F) -> GbDisplay where F: Facade {
        let (vertbuf, idxbuf) = {
            let topleft = Vertex {
                coord: [0.0, 0.0],
            };
            let topright = Vertex {
                coord: [BG_SIZE as f32, 0.0],
            };
            let bottomright = Vertex {
                coord: [BG_SIZE as f32, BG_SIZE as f32],
            };
            let bottomleft = Vertex {
                coord: [0.0, BG_SIZE as f32],
            };
            let vertices = vec![topleft, topright, bottomright, bottomleft];
            let indices = vec![0, 1, 3, 1, 2, 3];
            (
                VertexBuffer::new(display, &vertices).unwrap(),
                IndexBuffer::immutable(display, PrimitiveType::TrianglesList, &indices).unwrap()
            )
        };
        let colorprog = Program::from_source(display, SIMPLE_VERT, COLOR_FRAG, None).unwrap();
        let texprog = Program::from_source(display, SIMPLE_VERT, TEXTURE_FRAG, None).unwrap();
        let projection = {
            let orthomat = OrthoMat3::new(LCD_WIDTH as f32, LCD_HEIGHT as f32, 0.0, 1.0);
            // Reverse y coord, and translate origin to top left
            let adjust = Mat4::new(
                1.0f32, 0.0, 0.0, (LCD_WIDTH as f32) / -2.0,
                0.0, -1.0, 0.0, (LCD_HEIGHT as f32) / 2.0,
                0.0, 0.0, 1.0, 0.0,
                0.0, 0.0, 0.0, 1.0
                );
            orthomat.to_mat() * adjust
        };
        GbDisplay {
            simple_surface: vertbuf,
            simple_surface_idx: idxbuf,
            color_prog: colorprog,
            tex_prog: texprog,
            projection: projection,
            ly_counter: 0,
        }
    }

    pub fn inc_ly_counter(&mut self) -> u8 {
        if self.ly_counter >= 153 {
            self.ly_counter = 0;
        } else {
            self.ly_counter += 1;
        }
        self.ly_counter
    }

    pub fn set_ly_vblank(&mut self) -> u8 {
        self.ly_counter = 144;
        self.ly_counter
    }

    pub fn clear_viewport(&mut self, frame: &mut Frame, view: Rect, color: (f32, f32, f32, f32)) {
        let params = DrawParameters {
            viewport: Some(view),
            .. Default::default()
        };
        let uniforms = uniform! {
            projection: self.projection,
            translate: (0.0f32, 0.0),
            color: color,
        };
        frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.color_prog, &uniforms, &params);
    }

    pub fn draw<F>(&mut self, display: &F, frame: &mut Frame, view: Rect, mem: &AddressSpace) where F: Facade {
        let lcdc_reg = mem[0xFF40];
        let lcd_on                  = (lcdc_reg & 0x80) != 0;
        let win_map_addr            = if (lcdc_reg & 0x40) == 0 { 0x9800 } else { 0x9C00 };
        let win_on                  = (lcdc_reg & 0x20) != 0;
        let (tile_data, signed_idx) = if (lcdc_reg & 0x10) == 0 { (0x8800, false) }
                                        else { (0x8000, true) };
        let bg_map_addr             = if (lcdc_reg & 0x08) == 0 { 0x9800 } else { 0x9C00 };
        let sprite_height           = if (lcdc_reg & 0x04) == 0 { 8 } else { 16 };
        let sprite_on               = (lcdc_reg & 0x02) != 0;
        let bg_on                   = (lcdc_reg & 0x01) != 0;
        let scroll_y = mem[0xFF42];
        let scroll_x = mem[0xFF43];
        let bg_palette = build_palette(mem[0xFF47]);
        let sprite_palette0 = build_palette(mem[0xFF48]);
        let sprite_palette1 = build_palette(mem[0xFF49]);
        let win_y = mem[0xFF4A];
        let win_x = mem[0xFF4B];

        let params = DrawParameters {
            blend: Blend::alpha_blending(),
            viewport: Some(view),
            .. Default::default()
        };

        // Draw BG
        if bg_on {
            let opts = TileOpts {
                map_addr: bg_map_addr,
                tile_addr: tile_data,
                signed_idx: signed_idx,
                palette: bg_palette,
            };
            let bg_tex = build_tile_tex(display, mem, &opts);
            let uniforms = uniform! {
                projection: self.projection,
                translate: (scroll_x as f32, scroll_y as f32),
                tex: &bg_tex,
            };
            frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.tex_prog, &uniforms, &params);
        }

        // Draw window
        if win_on {
            let opts = TileOpts {
                map_addr: win_map_addr,
                tile_addr: tile_data,
                signed_idx: signed_idx,
                palette: bg_palette,
            };
            let win_tex = build_tile_tex(display, mem, &opts);
            let uniforms = uniform! {
                projection: self.projection,
                translate: (win_x as f32, win_y as f32),
                tex: &win_tex,
            };
            frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.tex_prog, &uniforms, &params);
        }
    }
}

const PALETTE_COLOR0: (f32, f32, f32, f32) = (1.0, 1.0, 1.0, 1.0);
const PALETTE_COLOR1: (f32, f32, f32, f32) = (0.25, 0.25, 0.25, 0.25);
const PALETTE_COLOR2: (f32, f32, f32, f32) = (0.75, 0.75, 0.75, 0.75);
const PALETTE_COLOR3: (f32, f32, f32, f32) = (0.0, 0.0, 0.0, 0.0);

fn build_palette(bits: u8) -> [(f32, f32, f32, f32); 4] {
    let c0 = bits & 0x03;
    let c1 = bits & 0x0C >> 2;
    let c2 = bits & 0x30 >> 4;
    let c3 = bits & 0xC0 >> 6;
    let mut colors = [PALETTE_COLOR0; 4];
    colors[c0 as usize] = PALETTE_COLOR0;
    colors[c1 as usize] = PALETTE_COLOR1;
    colors[c2 as usize] = PALETTE_COLOR2;
    colors[c3 as usize] = PALETTE_COLOR3;
    colors
}

struct TileOpts {
    map_addr: u16,
    tile_addr: u16,
    signed_idx: bool,
    palette: [(f32, f32, f32, f32); 4],
}

fn build_tile_tex<F>(display: &F, mem: &AddressSpace, opts: &TileOpts) -> Texture2d where F: Facade {
    // Data layout: data[y][x], origin top left
    let mut data: Vec<Vec<(f32, f32, f32, f32)>> = Vec::with_capacity(256);
    for i in 0..256 {
        data.push(Vec::with_capacity(256));
    }
    for i in 0..1024 {
        let offset: i32 = if opts.signed_idx {
            // Abuse conversion operations
            let tmp = mem[opts.map_addr + i] as i8;
            tmp as i32
        } else {
            mem[opts.map_addr + i] as i32
        };
        let addr = (opts.tile_addr as i32 + offset) as u16;
        let y_coord = i / 32;
        // Pixel format: big endian pixel pos
        for j in 0..8 {
            let lo = mem[addr + j*2];
            let hi = mem[addr + j*2 + 1];
            for k in (0..8).rev() {
                let mask = 1 << k;
                let color = ((lo & mask) >> k) | (((hi & mask) >> k) << 1);
                data[(y_coord + j) as usize].push(opts.palette[color as usize]);
            }
        }
    }
    Texture2d::new(display, data).unwrap()
}

pub fn calculate_viewport(width: u32, height: u32) -> Rect {
    let aspect = (width as f32) / (height as f32);
    if aspect > LCD_ASPECT {
        let fixwidth = ((height as f32) * LCD_ASPECT) as u32;
        Rect {
            left: (width - fixwidth) / 2,
            bottom: 0,
            width: fixwidth,
            height: height,
        }
    } else {
        let fixheight = ((width as f32) / LCD_ASPECT) as u32;
        Rect {
            left: 0,
            bottom: (height - fixheight) / 2,
            width: width,
            height: fixheight,
        }
    }
}
<commit_msg>Correct texture coordinates for BG surface<commit_after>use glium::VertexBuffer;
use glium::IndexBuffer;
use glium::Program;
use glium::DrawParameters;
use glium::Surface;
use glium::Frame;
use glium::Rect;
use glium::Texture2d;
use glium::Blend;
use glium::index::PrimitiveType;
use glium::backend::Facade;

use nalgebra::Mat4;
use nalgebra::OrthoMat3;

use mem::MemSection;
use mem::AddressSpace;

pub const LCD_WIDTH: u32    = 160;
pub const LCD_HEIGHT: u32   = 144;
pub const LCD_ASPECT: f32   = (LCD_WIDTH as f32) / (LCD_HEIGHT as f32);

pub const BG_SIZE: u32      = 256;

/// Period of the V-Blank in ns. V-Blank frequency is ~59.7 Hz
pub const VBLANK_PERIOD: u64 = 16_750_419;

/// Period of the H-Blank in ns. H-Blank frequency is ~9198 Hz
pub const HBLANK_PERIOD: u64 = 108_719;

static SIMPLE_VERT: &'static str = r#"
#version 140

in vec2 coord;
in vec2 tcoord;

out vec2 tex_coord;

uniform mat4 projection;
uniform vec2 translate;

void main() {
    tex_coord = tcoord;
    gl_Position = projection * vec4(coord.x + translate.x, coord.y + translate.y, 0.0, 1.0);
}
"#;

static COLOR_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform vec4 color;
uniform vec2 translate;

void main() {
    frag_color = color;
}
"#;

static TEXTURE_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform sampler2D tex;

void main() {
    frag_color = texture(tex, tex_coord);
}
"#;

#[derive(Copy, Clone)]
struct Vertex {
    coord: [f32; 2],
    tcoord: [f32; 2],
}

implement_vertex!(Vertex, coord, tcoord);

pub struct GbDisplay {
    simple_surface: VertexBuffer<Vertex>,
    simple_surface_idx: IndexBuffer<u32>,
    color_prog: Program,
    tex_prog: Program,
    projection: Mat4<f32>,
    ly_counter: u8,
}

impl GbDisplay {

    pub fn new<F>(display: &F) -> GbDisplay where F: Facade {
        let (vertbuf, idxbuf) = {
            let topleft = Vertex {
                coord: [0.0, 0.0],
                tcoord: [0.0, 1.0],
            };
            let topright = Vertex {
                coord: [BG_SIZE as f32, 0.0],
                tcoord: [1.0, 1.0],
            };
            let bottomright = Vertex {
                coord: [BG_SIZE as f32, BG_SIZE as f32],
                tcoord: [1.0, 0.0],
            };
            let bottomleft = Vertex {
                coord: [0.0, BG_SIZE as f32],
                tcoord: [0.0, 0.0],
            };
            let vertices = vec![topleft, topright, bottomright, bottomleft];
            let indices = vec![0, 1, 3, 1, 2, 3];
            (
                VertexBuffer::new(display, &vertices).unwrap(),
                IndexBuffer::immutable(display, PrimitiveType::TrianglesList, &indices).unwrap()
            )
        };
        let colorprog = Program::from_source(display, SIMPLE_VERT, COLOR_FRAG, None).unwrap();
        let texprog = Program::from_source(display, SIMPLE_VERT, TEXTURE_FRAG, None).unwrap();
        let projection = {
            let orthomat = OrthoMat3::new(LCD_WIDTH as f32, LCD_HEIGHT as f32, 0.0, 1.0);
            // Reverse y coord, and translate origin to top left
            let adjust = Mat4::new(
                1.0f32, 0.0, 0.0, (LCD_WIDTH as f32) / -2.0,
                0.0, -1.0, 0.0, (LCD_HEIGHT as f32) / 2.0,
                0.0, 0.0, 1.0, 0.0,
                0.0, 0.0, 0.0, 1.0
                );
            orthomat.to_mat() * adjust
        };
        GbDisplay {
            simple_surface: vertbuf,
            simple_surface_idx: idxbuf,
            color_prog: colorprog,
            tex_prog: texprog,
            projection: projection,
            ly_counter: 0,
        }
    }

    pub fn inc_ly_counter(&mut self) -> u8 {
        if self.ly_counter >= 153 {
            self.ly_counter = 0;
        } else {
            self.ly_counter += 1;
        }
        self.ly_counter
    }

    pub fn set_ly_vblank(&mut self) -> u8 {
        self.ly_counter = 144;
        self.ly_counter
    }

    pub fn clear_viewport(&mut self, frame: &mut Frame, view: Rect, color: (f32, f32, f32, f32)) {
        let params = DrawParameters {
            viewport: Some(view),
            .. Default::default()
        };
        let uniforms = uniform! {
            projection: self.projection,
            translate: (0.0f32, 0.0),
            color: color,
        };
        frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.color_prog, &uniforms, &params);
    }

    pub fn draw<F>(&mut self, display: &F, frame: &mut Frame, view: Rect, mem: &AddressSpace) where F: Facade {
        let lcdc_reg = mem[0xFF40];
        let lcd_on                  = (lcdc_reg & 0x80) != 0;
        let win_map_addr            = if (lcdc_reg & 0x40) == 0 { 0x9800 } else { 0x9C00 };
        let win_on                  = (lcdc_reg & 0x20) != 0;
        let (tile_data, signed_idx) = if (lcdc_reg & 0x10) == 0 { (0x8800, false) }
                                        else { (0x8000, true) };
        let bg_map_addr             = if (lcdc_reg & 0x08) == 0 { 0x9800 } else { 0x9C00 };
        let sprite_height           = if (lcdc_reg & 0x04) == 0 { 8 } else { 16 };
        let sprite_on               = (lcdc_reg & 0x02) != 0;
        let bg_on                   = (lcdc_reg & 0x01) != 0;
        let scroll_y = mem[0xFF42];
        let scroll_x = mem[0xFF43];
        let bg_palette = build_palette(mem[0xFF47]);
        let sprite_palette0 = build_palette(mem[0xFF48]);
        let sprite_palette1 = build_palette(mem[0xFF49]);
        let win_y = mem[0xFF4A];
        let win_x = mem[0xFF4B];

        let params = DrawParameters {
            blend: Blend::alpha_blending(),
            viewport: Some(view),
            .. Default::default()
        };

        // Draw BG
        if bg_on {
            let opts = TileOpts {
                map_addr: bg_map_addr,
                tile_addr: tile_data,
                signed_idx: signed_idx,
                palette: bg_palette,
            };
            let bg_tex = build_tile_tex(display, mem, &opts);
            let uniforms = uniform! {
                projection: self.projection,
                translate: (scroll_x as f32, scroll_y as f32),
                tex: &bg_tex,
            };
            frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.tex_prog, &uniforms, &params);
        }

        // Draw window
        if win_on {
            let opts = TileOpts {
                map_addr: win_map_addr,
                tile_addr: tile_data,
                signed_idx: signed_idx,
                palette: bg_palette,
            };
            let win_tex = build_tile_tex(display, mem, &opts);
            let uniforms = uniform! {
                projection: self.projection,
                translate: (win_x as f32, win_y as f32),
                tex: &win_tex,
            };
            frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.tex_prog, &uniforms, &params);
        }
    }
}

const PALETTE_COLOR0: (f32, f32, f32, f32) = (1.0, 1.0, 1.0, 1.0);
const PALETTE_COLOR1: (f32, f32, f32, f32) = (0.25, 0.25, 0.25, 0.25);
const PALETTE_COLOR2: (f32, f32, f32, f32) = (0.75, 0.75, 0.75, 0.75);
const PALETTE_COLOR3: (f32, f32, f32, f32) = (0.0, 0.0, 0.0, 0.0);

fn build_palette(bits: u8) -> [(f32, f32, f32, f32); 4] {
    let c0 = bits & 0x03;
    let c1 = bits & 0x0C >> 2;
    let c2 = bits & 0x30 >> 4;
    let c3 = bits & 0xC0 >> 6;
    let mut colors = [PALETTE_COLOR0; 4];
    colors[c0 as usize] = PALETTE_COLOR0;
    colors[c1 as usize] = PALETTE_COLOR1;
    colors[c2 as usize] = PALETTE_COLOR2;
    colors[c3 as usize] = PALETTE_COLOR3;
    colors
}

struct TileOpts {
    map_addr: u16,
    tile_addr: u16,
    signed_idx: bool,
    palette: [(f32, f32, f32, f32); 4],
}

fn build_tile_tex<F>(display: &F, mem: &AddressSpace, opts: &TileOpts) -> Texture2d where F: Facade {
    // Data layout: data[y][x], origin top left
    let mut data: Vec<Vec<(f32, f32, f32, f32)>> = Vec::with_capacity(256);
    for i in 0..256 {
        data.push(Vec::with_capacity(256));
    }
    for i in 0..1024 {
        let offset: i32 = if opts.signed_idx {
            // Abuse conversion operations
            let tmp = mem[opts.map_addr + i] as i8;
            tmp as i32
        } else {
            mem[opts.map_addr + i] as i32
        };
        let addr = (opts.tile_addr as i32 + offset) as u16;
        let y_coord = i / 32;
        // Pixel format: big endian pixel pos
        for j in 0..8 {
            let lo = mem[addr + j*2];
            let hi = mem[addr + j*2 + 1];
            for k in (0..8).rev() {
                let mask = 1 << k;
                let color = ((lo & mask) >> k) | (((hi & mask) >> k) << 1);
                data[(y_coord + j) as usize].push(opts.palette[color as usize]);
            }
        }
    }
    Texture2d::new(display, data).unwrap()
}

pub fn calculate_viewport(width: u32, height: u32) -> Rect {
    let aspect = (width as f32) / (height as f32);
    if aspect > LCD_ASPECT {
        let fixwidth = ((height as f32) * LCD_ASPECT) as u32;
        Rect {
            left: (width - fixwidth) / 2,
            bottom: 0,
            width: fixwidth,
            height: height,
        }
    } else {
        let fixheight = ((width as f32) / LCD_ASPECT) as u32;
        Rect {
            left: 0,
            bottom: (height - fixheight) / 2,
            width: width,
            height: fixheight,
        }
    }
}
<|endoftext|>


<commit_before>// rustfmt-normalize_comments: true
// rustfmt-single_line_if_else_max_width: 0
// rustfmt-indent_style: Visual
// Test chain formatting.

fn main() {
    // Don't put chains on a single line if it wasn't so in source.
    let a = b.c.d.1.foo(|x| x + 1);

    bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
                       .ddddddddddddddddddddddddddd();

    bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
                       .ddddddddddddddddddddddddddd
                       .eeeeeeee();

    // Test case where first chain element isn't a path, but is shorter than
    // the size of a tab.
    x().y(|| match cond() {
              true => (),
              false => (),
          });

    loong_func().quux(move || if true {
                          1
                      } else {
                          2
                      });

    some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
        let x = c;
        x
    });

    some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
        let x = c;
        x
    })
                           .method_call_b(aaaaa, bbbbb, |c| {
        let x = c;
        x
    });

    fffffffffffffffffffffffffffffffffff(a, {
        SCRIPT_TASK_ROOT.with(|root| {
            *root.borrow_mut() = Some(&script_task);
        });
    });

    let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
                                                                          .map(|x| x / 2)
                                                                          .fold(0,
                                                                                |acc, x| acc + x);

    aaaaaaaaaaaaaaaa.map(|x| {
        x += 1;
        x
    })
                    .filter(some_mod::some_filter)
}

fn floaters() {
    let z = Foo { field1: val1,
                  field2: val2, };

    let x = Foo { field1: val1,
                  field2: val2, }.method_call()
            .method_call();

    let y = if cond {
                val1
            } else {
                val2
            }.method_call();

    {
        match x {
            PushParam => {
                // params are 1-indexed
                stack.push(mparams[match cur.to_digit(10) {
                                       Some(d) => d as usize - 1,
                                       None => return Err("bad param number".to_owned()),
                                   }].clone());
            }
        }
    }

    if cond {
        some();
    } else {
        none();
    }.bar()
    .baz();

    Foo { x: val }.baz(|| {
        force();
        multiline();
    })
                  .quux();

    Foo { y: i_am_multi_line,
          z: ok, }.baz(|| {
        force();
        multiline();
    })
    .quux();

    a + match x {
            true => "yay!",
            false => "boo!",
        }.bar()
}

fn is_replaced_content() -> bool {
    constellat.send(ConstellationMsg::ViewportConstrained(self.id, constraints))
              .unwrap();
}

fn issue587() {
    a.b::<()>(c);

    std::mem::transmute(dl.symbol::<()>("init").unwrap())
}

fn issue_1389() {
    let names = String::from_utf8(names)?.split('|')
                                         .map(str::to_owned)
                                         .collect();
}

fn issue1217() -> Result<Mnemonic, Error> {
    let random_chars: String = OsRng::new()?.gen_ascii_chars()
                                            .take(self.bit_length)
                                            .collect();

    Ok(Mnemonic::new(&random_chars))
}

fn issue1236(options: Vec<String>) -> Result<Option<String>> {
    let process = Command::new("dmenu").stdin(Stdio::piped())
                                       .stdout(Stdio::piped())
                                       .spawn()
                                       .chain_err(|| "failed to spawn dmenu")?;
}

fn issue1434() {
    for _ in 0..100 {
        let prototype_id =
            PrototypeIdData::from_reader::<_, B>(&mut self.file_cursor).chain_err(|| {
                format!("could not read prototype ID at offset {:#010x}",
                        current_offset)
            })?;
    }
}
<commit_msg>Fix chains-visual test<commit_after>// rustfmt-normalize_comments: true
// rustfmt-single_line_if_else_max_width: 0
// rustfmt-indent_style: Visual
// Test chain formatting.

fn main() {
    // Don't put chains on a single line if it wasn't so in source.
    let a = b.c.d.1.foo(|x| x + 1);

    bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
                       .ddddddddddddddddddddddddddd();

    bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
                       .ddddddddddddddddddddddddddd
                       .eeeeeeee();

    // Test case where first chain element isn't a path, but is shorter than
    // the size of a tab.
    x().y(|| match cond() {
              true => (),
              false => (),
          });

    loong_func().quux(move || if true {
                          1
                      } else {
                          2
                      });

    some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
        let x = c;
        x
    });

    some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
        let x = c;
        x
    })
                           .method_call_b(aaaaa, bbbbb, |c| {
        let x = c;
        x
    });

    fffffffffffffffffffffffffffffffffff(a, {
        SCRIPT_TASK_ROOT.with(|root| {
                                  *root.borrow_mut() = Some(&script_task);
                              });
    });

    let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
                                                                          .map(|x| x / 2)
                                                                          .fold(0,
                                                                                |acc, x| acc + x);

    aaaaaaaaaaaaaaaa.map(|x| {
                             x += 1;
                             x
                         })
                    .filter(some_mod::some_filter)
}

fn floaters() {
    let z = Foo { field1: val1,
                  field2: val2, };

    let x = Foo { field1: val1,
                  field2: val2, }.method_call()
            .method_call();

    let y = if cond {
                val1
            } else {
                val2
            }.method_call();

    {
        match x {
            PushParam => {
                // params are 1-indexed
                stack.push(mparams[match cur.to_digit(10) {
                                       Some(d) => d as usize - 1,
                                       None => return Err("bad param number".to_owned()),
                                   }].clone());
            }
        }
    }

    if cond {
        some();
    } else {
        none();
    }.bar()
    .baz();

    Foo { x: val }.baz(|| {
                           force();
                           multiline();
                       })
                  .quux();

    Foo { y: i_am_multi_line,
          z: ok, }.baz(|| {
             force();
             multiline();
         })
    .quux();

    a + match x {
            true => "yay!",
            false => "boo!",
        }.bar()
}

fn is_replaced_content() -> bool {
    constellat.send(ConstellationMsg::ViewportConstrained(self.id, constraints))
              .unwrap();
}

fn issue587() {
    a.b::<()>(c);

    std::mem::transmute(dl.symbol::<()>("init").unwrap())
}

fn issue_1389() {
    let names = String::from_utf8(names)?.split('|')
                                         .map(str::to_owned)
                                         .collect();
}

fn issue1217() -> Result<Mnemonic, Error> {
    let random_chars: String = OsRng::new()?.gen_ascii_chars()
                                            .take(self.bit_length)
                                            .collect();

    Ok(Mnemonic::new(&random_chars))
}

fn issue1236(options: Vec<String>) -> Result<Option<String>> {
    let process = Command::new("dmenu").stdin(Stdio::piped())
                                       .stdout(Stdio::piped())
                                       .spawn()
                                       .chain_err(|| "failed to spawn dmenu")?;
}

fn issue1434() {
    for _ in 0..100 {
        let prototype_id =
            PrototypeIdData::from_reader::<_, B>(&mut self.file_cursor).chain_err(|| {
                format!("could not read prototype ID at offset {:#010x}",
                        current_offset)
            })?;
    }
}
<|endoftext|>


<commit_before><commit_msg>continue the great migration<commit_after><|endoftext|>


<commit_before>use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender};

use std::io::prelude::*;

extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use self::uuid::Uuid;

use client::{Client,ClientBase};
use chat::{read_text,text_as_bytes};
use distributor::Distributor;
use distributor::Kind as DistKind;
use store::{DataStore,Store};
use player::Player;

#[derive(Debug,Clone)]
pub struct Server {
    clients: Arc<Mutex<Vec<ClientBase>>>, // this always grows
    players: Arc<Mutex<HashMap<Uuid, Player>>>, //NOTE: this may make more sense as atomic-vec-keys
    dist: Sender<DistKind<TcpStream>>,
    store: Arc<Mutex<Store>>, //NOTE: this may become a threadpool
}

impl Server {
    pub fn new(ip: &str) {
        let listener = TcpListener::bind(ip).unwrap();

        let (dist_tx, mut distributor) = Distributor::new(Store::default());
        thread::spawn(move || distributor.run());

        let server = Server {
            clients: Arc::new(Mutex::new(vec!())),
            players: Arc::new(Mutex::new(HashMap::new())),
            dist: dist_tx,
            store: Arc::new(Mutex::new(Store::default())),
        };

        if let Ok(mut clients) = server.clients.lock() {
            if let Ok(store) = server.store.lock() {
                *clients = store.clients_get();
            }
        }

        for s in listener.incoming() {
            match s {
                Ok(s) => {
                    let server = server.clone();
                    thread::spawn(|| Server::handler(server,s));
                },
                _ => {},
            }
        }
    }

    #[allow(unused_must_use)]
    fn handler (mut server: Server, mut s: TcpStream) {
        let mut cmd = [0;1];

        //new conn needs auth code
        let m = uuid::Uuid::new_v4();
        s.write_all(m.as_bytes());

        let mut client_id: Option<Uuid> = None;

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    0 => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_players(&mut server, uuid);
                        }
                    },
                    1 => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                2 => { //chat
                                    Server::chat(&mut server, &mut s, uuid);
                                },
                                3 => { //player
                                    if let (_, Some(player)) = Player::from_stream(&mut s, false) {
                                        if let Ok(store) = server.store.lock() {
                                            if store.player_update(&uuid, &player) {
                                                let data = Player::to_bytes(Some(&uuid),&player);
                                                server.dist.send(DistKind::Broadcast(data));

                                                println!("nick_change:{:?}  {:?}",uuid,player);
                                            }
                                        }
                                    }
                                },
                                _ => panic!("unknown cmd:{:?}",cmd)
                            }
                        }
                    }
                }
            }
            else { break } //drop dead client
        }

        println!("client dropped");
    }

    fn register (server: &mut Server,
                 mut s: &mut TcpStream,) {
        if let Some(c) = Client::load(&mut s) {

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() { panic!("client already register {:?}",c.id()) }
                }
            }

            if let Ok(store) = server.store.lock() {
                let mut r = false;
                for _ in [..100].iter() { // try to repeatedly add a unique name
                    r = store.player_put(&c.id(), &Player::default());
                    if r { break }
                }

                if r {
                    let r = store.client_put(&c.base);
                    println!("registered ({:?}):{:?}",r, c.id());

                    if let Ok(mut clients) = server.clients.lock() {
                        clients.push(c.base);
                    }
                }

            }
        }
    }

    #[allow(unused_must_use)]
    fn chat (server: &mut Server,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            println!("chat-client:{:?}",text.trim());

            //broadcast
            let (mut data, bytes) = text_as_bytes(&text);
            data.extend_from_slice(bytes);
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

            server.dist.send(DistKind::Broadcast(data));
        }
    }

    #[allow(unused_must_use)]
    fn login (server: &mut Server,
              mut s: &mut TcpStream,
              m: Uuid) -> Option<Uuid> {
        let mut client_id = None;
        let mut player = None;

        if let Some(c) = Client::load(&mut s) {
            let mut reg_key = None;

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() {
                        reg_key = Some(n.key.clone());
                        client_id = Some(c.id().clone());

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {

                    if let Ok(store) = server.store.lock() {
                        player = store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                server.dist.send(DistKind::Add(*c.id(),stmp));

                                if let Ok(mut players) = server.players.lock() {
                                    players.insert(*c.id(),player.clone());
                                    println!("total players:{:?}",players.len()); //NOTE: this should print on debug only
                                }
                            }

                            println!("login:{:?}",c.id());
                            let data = Player::to_bytes(Some(c.id()),&player);
                            server.dist.send(DistKind::Broadcast(data));
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

            }
            else { panic!("client unregistered {:?}", c) }
        }

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_players (server: &mut Server,
                     uuid: Uuid)  {

        if let Ok(players) = server.players.lock() {
            for (ref pid,player) in players.iter() {
                let data = Player::to_bytes(Some(pid),&player);

                server.dist.send(DistKind::Select(uuid,data));
            }

        }
    }
}
<commit_msg>rename<commit_after>use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{Sender};

use std::io::prelude::*;

extern crate hmacsha1;
extern crate uuid;
extern crate byteorder;

use self::uuid::Uuid;

use client::{Client,ClientBase};
use chat::{read_text,text_as_bytes};
use distributor::Distributor;
use distributor::Kind as DistKind;
use store::{DataStore,Store};
use player::Player;

#[derive(Debug,Clone)]
pub struct Server {
    clients: Arc<Mutex<Vec<ClientBase>>>, // this always grows
    players: Arc<Mutex<HashMap<Uuid, Player>>>, //NOTE: this may make more sense as atomic-vec-keys
    dist: Sender<DistKind<TcpStream>>,
    store: Arc<Mutex<Store>>, //NOTE: this may become a threadpool
}

impl Server {
    pub fn new(ip: &str) {
        let listener = TcpListener::bind(ip).unwrap();

        let (dist_tx, mut distributor) = Distributor::new(Store::default());
        thread::spawn(move || distributor.run());

        let server = Server {
            clients: Arc::new(Mutex::new(vec!())),
            players: Arc::new(Mutex::new(HashMap::new())),
            dist: dist_tx,
            store: Arc::new(Mutex::new(Store::default())),
        };

        if let Ok(mut clients) = server.clients.lock() {
            if let Ok(store) = server.store.lock() {
                *clients = store.clients_get();
            }
        }

        for s in listener.incoming() {
            match s {
                Ok(s) => {
                    let server = server.clone();
                    thread::spawn(|| Server::handler(server,s));
                },
                _ => {},
            }
        }
    }

    #[allow(unused_must_use)]
    fn handler (mut server: Server, mut s: TcpStream) {
        let mut cmd = [0;1];

        //new conn needs auth code
        let m = uuid::Uuid::new_v4();
        s.write_all(m.as_bytes());

        let mut client_id: Option<Uuid> = None;

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    0 => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_players(&mut server, uuid);
                        }
                    },
                    1 => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                2 => { //chat
                                    Server::handle_chat(&mut server, &mut s, uuid);
                                },
                                3 => { //player
                                    if let (_, Some(player)) = Player::from_stream(&mut s, false) {
                                        if let Ok(store) = server.store.lock() {
                                            if store.player_update(&uuid, &player) {
                                                let data = Player::to_bytes(Some(&uuid),&player);
                                                server.dist.send(DistKind::Broadcast(data));

                                                println!("nick_change:{:?}  {:?}",uuid,player);
                                            }
                                        }
                                    }
                                },
                                _ => panic!("unknown cmd:{:?}",cmd)
                            }
                        }
                    }
                }
            }
            else { break } //drop dead client
        }

        println!("client dropped");
    }

    fn register (server: &mut Server,
                 mut s: &mut TcpStream,) {
        if let Some(c) = Client::load(&mut s) {

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() { panic!("client already register {:?}",c.id()) }
                }
            }

            if let Ok(store) = server.store.lock() {
                let mut r = false;
                for _ in [..100].iter() { // try to repeatedly add a unique name
                    r = store.player_put(&c.id(), &Player::default());
                    if r { break }
                }

                if r {
                    let r = store.client_put(&c.base);
                    println!("registered ({:?}):{:?}",r, c.id());

                    if let Ok(mut clients) = server.clients.lock() {
                        clients.push(c.base);
                    }
                }

            }
        }
    }

    #[allow(unused_must_use)]
    fn handle_chat (server: &mut Server,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            println!("chat-client:{:?}",text.trim());

            //broadcast
            let (mut data, bytes) = text_as_bytes(&text);
            data.extend_from_slice(bytes);
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

            server.dist.send(DistKind::Broadcast(data));
        }
    }

    #[allow(unused_must_use)]
    fn login (server: &mut Server,
              mut s: &mut TcpStream,
              m: Uuid) -> Option<Uuid> {
        let mut client_id = None;
        let mut player = None;

        if let Some(c) = Client::load(&mut s) {
            let mut reg_key = None;

            if let Ok(clients) = server.clients.lock() {
                for n in clients.iter() {
                    if &n.id == c.id() {
                        reg_key = Some(n.key.clone());
                        client_id = Some(c.id().clone());

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {

                    if let Ok(store) = server.store.lock() {
                        player = store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                server.dist.send(DistKind::Add(*c.id(),stmp));

                                if let Ok(mut players) = server.players.lock() {
                                    players.insert(*c.id(),player.clone());
                                    println!("total players:{:?}",players.len()); //NOTE: this should print on debug only
                                }
                            }

                            println!("login:{:?}",c.id());
                            let data = Player::to_bytes(Some(c.id()),&player);
                            server.dist.send(DistKind::Broadcast(data));
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

            }
            else { panic!("client unregistered {:?}", c) }
        }

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_players (server: &mut Server,
                     uuid: Uuid)  {

        if let Ok(players) = server.players.lock() {
            for (ref pid,player) in players.iter() {
                let data = Player::to_bytes(Some(pid),&player);

                server.dist.send(DistKind::Select(uuid,data));
            }

        }
    }
}
<|endoftext|>


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

//!
//! Implements the Roughenough server functionality.
//!

use hex;
use std::io::ErrorKind;
use std::net::SocketAddr;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use std::io::Write;

use byteorder::{LittleEndian, WriteBytesExt};

use humansize::{FileSize, file_size_opts as fsopts};

use mio::net::{TcpListener, UdpSocket};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio::tcp::Shutdown;
use mio_extras::timer::Timer;

use crate::{Error, RtMessage, Tag, MIN_REQUEST_LENGTH};
use crate::config::ServerConfig;
use crate::grease::Grease;
use crate::key::{LongTermKey, OnlineKey};
use crate::kms;
use crate::merkle::MerkleTree;
use crate::stats::{AggregatedStats, PerClientStats, ServerStats};

macro_rules! check_ctrlc {
    ($keep_running:expr) => {
        if !$keep_running.load(Ordering::Acquire) {
            warn!("Ctrl-C caught, exiting...");
            return true;
        }
    };
}

// mio event registrations
const MESSAGE: Token = Token(0);
const STATUS: Token = Token(1);
const HEALTH_CHECK: Token = Token(2);

// Canned response to health check request
const HTTP_RESPONSE: &str = "HTTP/1.1 200 OK\nContent-Length: 0\nConnection: close\n\n";

/// The main Roughenough server instance.
///
/// The [ServerConfig](../config/trait.ServerConfig.html) trait specifies the required and optional
/// parameters available for configuring a Roughenoguh server instance.
///
/// Implementations of `ServerConfig` obtain configurations from different back-end sources
/// such as files or environment variables.
///
/// See [the config module](../config/index.html) for more information.
///
pub struct Server {
    config: Box<dyn ServerConfig>,
    online_key: OnlineKey,
    cert_bytes: Vec<u8>,

    socket: UdpSocket,
    health_listener: Option<TcpListener>,
    keep_running: Arc<AtomicBool>,
    poll_duration: Option<Duration>,
    grease: Grease,
    timer: Timer<()>,
    poll: Poll,
    merkle: MerkleTree,
    requests: Vec<(Vec<u8>, SocketAddr)>,
    buf: [u8; 65_536],

    public_key: String,

    stats: Box<dyn ServerStats>,

    // Used to send requests to ourselves in fuzzing mode
    #[cfg(fuzzing)]
    fake_client_socket: UdpSocket,
}

impl Server {
    ///
    /// Create a new server instance from the provided
    /// [`ServerConfig`](../config/trait.ServerConfig.html) trait object instance.
    ///
    pub fn new(config: Box<dyn ServerConfig>) -> Server {
        let online_key = OnlineKey::new();
        let public_key: String;

        let cert_bytes = {
            let seed = match kms::load_seed(config.as_ref()) {
                Ok(seed) => seed,
                Err(e) => {
                    error!("Failed to load seed: {:#?}", e);
                    process::exit(1);
                }
            };
            let mut long_term_key = LongTermKey::new(&seed);
            public_key = hex::encode(long_term_key.public_key());

            long_term_key.make_cert(&online_key).encode().unwrap()
        };

        let keep_running = Arc::new(AtomicBool::new(true));

        let sock_addr = config.udp_socket_addr().expect("udp sock addr");
        let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");

        let poll_duration = Some(Duration::from_millis(100));

        let mut timer: Timer<()> = Timer::default();
        timer.set_timeout(config.status_interval(), ());

        let poll = Poll::new().unwrap();
        poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
            .unwrap();
        poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
            .unwrap();

        let health_listener = if let Some(hc_port) = config.health_check_port() {
            let hc_sock_addr: SocketAddr = format!("{}:{}", config.interface(), hc_port)
                .parse()
                .unwrap();

            let tcp_listener = TcpListener::bind(&hc_sock_addr)
                .expect("failed to bind TCP listener for health check");

            poll.register(&tcp_listener, HEALTH_CHECK, Ready::readable(), PollOpt::edge())
                .unwrap();

            Some(tcp_listener)
        } else {
            None
        };

        let stats: Box<dyn ServerStats> = if config.client_stats_enabled() {
            Box::new(PerClientStats::new())
        } else {
            Box::new(AggregatedStats::new())
        };

        let grease = Grease::new(config.fault_percentage());
        let merkle = MerkleTree::new();
        let requests = Vec::with_capacity(config.batch_size() as usize);

        Server {
            config,
            online_key,
            cert_bytes,

            socket,
            health_listener,

            keep_running,
            poll_duration,
            grease,
            timer,
            poll,
            merkle,
            requests,
            buf: [0u8; 65_536],

            public_key,

            stats,

            #[cfg(fuzzing)]
            fake_client_socket: UdpSocket::bind(&"127.0.0.1:0".parse().unwrap()).unwrap(),
        }
    }

    /// Returns a reference to the server's long-term public key
    pub fn get_public_key(&self) -> &str {
        &self.public_key
    }

    /// Returns a reference to the server's on-line (delegated) key
    pub fn get_online_key(&self) -> &OnlineKey {
        &self.online_key
    }

    /// Returns a reference to the `ServerConfig` this server was configured with
    pub fn get_config(&self) -> &dyn ServerConfig {
        self.config.as_ref()
    }

    /// Returns a reference counted pointer the this server's `keep_running` value.
    pub fn get_keep_running(&self) -> Arc<AtomicBool> {
        self.keep_running.clone()
    }

    #[cfg(fuzzing)]
    pub fn send_to_self(&mut self, data: &[u8]) {
        let res = self
            .fake_client_socket
            .send_to(data, &self.socket.local_addr().unwrap());
        info!("Sent to self: {:?}", res);
    }

    /// The main processing function for incoming connections. This method should be
    /// called repeatedly in a loop to process requests. It returns 'true' when the
    /// server has shutdown (due to keep_running being set to 'false').
    ///
    pub fn process_events(&mut self, events: &mut Events) -> bool {
        self.poll
            .poll(events, self.poll_duration)
            .expect("server event poll failed; cannot recover");

        for msg in events.iter() {
            match msg.token() {
                MESSAGE => {
                    loop {
                        check_ctrlc!(self.keep_running);

                        self.merkle.reset();
                        self.requests.clear();

                        let socket_now_empty = self.collect_requests();

                        if self.requests.is_empty() {
                            break;
                        }

                        self.send_responses();

                        if socket_now_empty {
                            break;
                        }
                    }
                }

                HEALTH_CHECK => {
                    let listener = self.health_listener.as_ref().unwrap();

                    match listener.accept() {
                        Ok((ref mut stream, src_addr)) => {
                            info!("health check from {}", src_addr);
                            self.stats.add_health_check(&src_addr.ip());

                            match stream.write(HTTP_RESPONSE.as_bytes()) {
                                Ok(_) => (),
                                Err(e) => warn!("error writing health check {}", e),
                            };

                            match stream.shutdown(Shutdown::Both) {
                                Ok(_) => (),
                                Err(e) => warn!("error in health check socket shutdown {}", e),
                            }
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                            debug!("blocking in TCP health check");
                        }
                        Err(e) => {
                            warn!("unexpected health check error {}", e);
                        }
                    }
                }

                STATUS => {
                    for (addr, counts) in self.stats.iter() {
                        info!(
                            "{:16}: {} valid, {} invalid requests; {} responses ({} sent)",
                            format!("{}", addr), counts.valid_requests, counts.invalid_requests,
                            counts.responses_sent,
                            counts.bytes_sent.file_size(fsopts::BINARY).unwrap()
                        );
                    }

                    info!(
                        "Totals: {} unique clients; {} valid, {} invalid requests; {} responses ({} sent)",
                        self.stats.total_unique_clients(),
                        self.stats.total_valid_requests(), self.stats.total_invalid_requests(),
                        self.stats.total_responses_sent(),
                        self.stats.total_bytes_sent().file_size(fsopts::BINARY).unwrap()
                    );

                    self.timer.set_timeout(self.config.status_interval(), ());
                }

                _ => unreachable!(),
            }
        }
        false
    }

    // Read and process client requests from socket until empty or 'batch_size' number of
    // requests have been read.
    fn collect_requests(&mut self) -> bool {
        for i in 0..self.config.batch_size() {
            match self.socket.recv_from(&mut self.buf) {
                Ok((num_bytes, src_addr)) => {
                    match self.nonce_from_request(&self.buf, num_bytes) {
                        Ok(nonce) => {
                            self.stats.add_valid_request(&src_addr.ip());
                            self.requests.push((Vec::from(nonce), src_addr));
                            self.merkle.push_leaf(nonce);
                        }
                        Err(e) => {
                            self.stats.add_invalid_request(&src_addr.ip());

                            info!(
                                "Invalid request: '{:?}' ({} bytes) from {} (#{} in batch, resp #{})",
                                e, num_bytes, src_addr, i,
                                self.stats.total_responses_sent() + u64::from(i)
                            );
                        }
                    }
                }
                Err(e) => match e.kind() {
                    ErrorKind::WouldBlock => {
                        return true;
                    }
                    _ => {
                        error!("Error receiving from socket: {:?}: {:?}", e.kind(), e);
                        return false;
                    }
                },
            };
        }

        false
    }

    // extract the client's nonce from its request
    fn nonce_from_request<'a>(&self, buf: &'a [u8], num_bytes: usize) -> Result<&'a [u8], Error> {
        if num_bytes < MIN_REQUEST_LENGTH as usize {
            return Err(Error::RequestTooShort);
        }

        let tag_count = &buf[..4];
        let expected_nonc = &buf[8..12];
        let expected_pad = &buf[12..16];

        let tag_count_is_2 = tag_count == [0x02, 0x00, 0x00, 0x00];
        let tag1_is_nonc = expected_nonc == Tag::NONC.wire_value();
        let tag2_is_pad = expected_pad == Tag::PAD.wire_value();

        if tag_count_is_2 && tag1_is_nonc && tag2_is_pad {
            Ok(&buf[0x10..0x50])
        } else {
            Err(Error::InvalidRequest)
        }
    }

    fn send_responses(&mut self) {
        let merkle_root = self.merkle.compute_root();

        // The SREP tag is identical for each response
        let srep = self.online_key.make_srep(SystemTime::now(), &merkle_root);

        for (i, &(ref nonce, ref src_addr)) in self.requests.iter().enumerate() {
            let paths = self.merkle.get_paths(i);
            let resp_msg = {
                let r = self.make_response(&srep, &self.cert_bytes, &paths, i as u32);
                if self.grease.should_add_error() { self.grease.add_errors(&r) } else { r }
            };
            let resp_bytes = resp_msg.encode().unwrap();

            let bytes_sent = self
                .socket
                .send_to(&resp_bytes, &src_addr)
                .expect("send_to failed");

            self.stats.add_response(&src_addr.ip(), bytes_sent);

            info!(
                "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})",
                bytes_sent,
                src_addr,
                hex::encode(&nonce[0..4]),
                i + 1,
                self.stats.total_responses_sent()
            );
        }
    }

    fn make_response(&self, srep: &RtMessage, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage {
        let mut index = [0; 4];
        (&mut index as &mut [u8])
            .write_u32::<LittleEndian>(idx)
            .unwrap();

        let sig_bytes = srep.get_field(Tag::SIG).unwrap();
        let srep_bytes = srep.get_field(Tag::SREP).unwrap();

        let mut response = RtMessage::new(5);
        response.add_field(Tag::SIG, sig_bytes).unwrap();
        response.add_field(Tag::PATH, path).unwrap();
        response.add_field(Tag::SREP, srep_bytes).unwrap();
        response.add_field(Tag::CERT, cert_bytes).unwrap();
        response.add_field(Tag::INDX, &index).unwrap();

        response
    }
}
<commit_msg>stats: display clients sorted by number of valid requests<commit_after>// Copyright 2017-2019 int08h LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//!
//! Implements the Roughenough server functionality.
//!

use hex;
use std::io::ErrorKind;
use std::net::{SocketAddr, IpAddr};
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use std::io::Write;

use byteorder::{LittleEndian, WriteBytesExt};

use humansize::{FileSize, file_size_opts as fsopts};

use mio::net::{TcpListener, UdpSocket};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio::tcp::Shutdown;
use mio_extras::timer::Timer;

use crate::{Error, RtMessage, Tag, MIN_REQUEST_LENGTH};
use crate::config::ServerConfig;
use crate::grease::Grease;
use crate::key::{LongTermKey, OnlineKey};
use crate::kms;
use crate::merkle::MerkleTree;
use crate::stats::{AggregatedStats, PerClientStats, ServerStats, ClientStatEntry};

macro_rules! check_ctrlc {
    ($keep_running:expr) => {
        if !$keep_running.load(Ordering::Acquire) {
            warn!("Ctrl-C caught, exiting...");
            return true;
        }
    };
}

// mio event registrations
const MESSAGE: Token = Token(0);
const STATUS: Token = Token(1);
const HEALTH_CHECK: Token = Token(2);

// Canned response to health check request
const HTTP_RESPONSE: &str = "HTTP/1.1 200 OK\nContent-Length: 0\nConnection: close\n\n";

/// The main Roughenough server instance.
///
/// The [ServerConfig](../config/trait.ServerConfig.html) trait specifies the required and optional
/// parameters available for configuring a Roughenoguh server instance.
///
/// Implementations of `ServerConfig` obtain configurations from different back-end sources
/// such as files or environment variables.
///
/// See [the config module](../config/index.html) for more information.
///
pub struct Server {
    config: Box<dyn ServerConfig>,
    online_key: OnlineKey,
    cert_bytes: Vec<u8>,

    socket: UdpSocket,
    health_listener: Option<TcpListener>,
    keep_running: Arc<AtomicBool>,
    poll_duration: Option<Duration>,
    grease: Grease,
    timer: Timer<()>,
    poll: Poll,
    merkle: MerkleTree,
    requests: Vec<(Vec<u8>, SocketAddr)>,
    buf: [u8; 65_536],

    public_key: String,

    stats: Box<dyn ServerStats>,

    // Used to send requests to ourselves in fuzzing mode
    #[cfg(fuzzing)]
    fake_client_socket: UdpSocket,
}

impl Server {
    ///
    /// Create a new server instance from the provided
    /// [`ServerConfig`](../config/trait.ServerConfig.html) trait object instance.
    ///
    pub fn new(config: Box<dyn ServerConfig>) -> Server {
        let online_key = OnlineKey::new();
        let public_key: String;

        let cert_bytes = {
            let seed = match kms::load_seed(config.as_ref()) {
                Ok(seed) => seed,
                Err(e) => {
                    error!("Failed to load seed: {:#?}", e);
                    process::exit(1);
                }
            };
            let mut long_term_key = LongTermKey::new(&seed);
            public_key = hex::encode(long_term_key.public_key());

            long_term_key.make_cert(&online_key).encode().unwrap()
        };

        let keep_running = Arc::new(AtomicBool::new(true));

        let sock_addr = config.udp_socket_addr().expect("udp sock addr");
        let socket = UdpSocket::bind(&sock_addr).expect("failed to bind to socket");

        let poll_duration = Some(Duration::from_millis(100));

        let mut timer: Timer<()> = Timer::default();
        timer.set_timeout(config.status_interval(), ());

        let poll = Poll::new().unwrap();
        poll.register(&socket, MESSAGE, Ready::readable(), PollOpt::edge())
            .unwrap();
        poll.register(&timer, STATUS, Ready::readable(), PollOpt::edge())
            .unwrap();

        let health_listener = if let Some(hc_port) = config.health_check_port() {
            let hc_sock_addr: SocketAddr = format!("{}:{}", config.interface(), hc_port)
                .parse()
                .unwrap();

            let tcp_listener = TcpListener::bind(&hc_sock_addr)
                .expect("failed to bind TCP listener for health check");

            poll.register(&tcp_listener, HEALTH_CHECK, Ready::readable(), PollOpt::edge())
                .unwrap();

            Some(tcp_listener)
        } else {
            None
        };

        let stats: Box<dyn ServerStats> = if config.client_stats_enabled() {
            Box::new(PerClientStats::new())
        } else {
            Box::new(AggregatedStats::new())
        };

        let grease = Grease::new(config.fault_percentage());
        let merkle = MerkleTree::new();
        let requests = Vec::with_capacity(config.batch_size() as usize);

        Server {
            config,
            online_key,
            cert_bytes,

            socket,
            health_listener,

            keep_running,
            poll_duration,
            grease,
            timer,
            poll,
            merkle,
            requests,
            buf: [0u8; 65_536],

            public_key,

            stats,

            #[cfg(fuzzing)]
            fake_client_socket: UdpSocket::bind(&"127.0.0.1:0".parse().unwrap()).unwrap(),
        }
    }

    /// Returns a reference to the server's long-term public key
    pub fn get_public_key(&self) -> &str {
        &self.public_key
    }

    /// Returns a reference to the server's on-line (delegated) key
    pub fn get_online_key(&self) -> &OnlineKey {
        &self.online_key
    }

    /// Returns a reference to the `ServerConfig` this server was configured with
    pub fn get_config(&self) -> &dyn ServerConfig {
        self.config.as_ref()
    }

    /// Returns a reference counted pointer the this server's `keep_running` value.
    pub fn get_keep_running(&self) -> Arc<AtomicBool> {
        self.keep_running.clone()
    }

    #[cfg(fuzzing)]
    pub fn send_to_self(&mut self, data: &[u8]) {
        let res = self
            .fake_client_socket
            .send_to(data, &self.socket.local_addr().unwrap());
        info!("Sent to self: {:?}", res);
    }

    /// The main processing function for incoming connections. This method should be
    /// called repeatedly in a loop to process requests. It returns 'true' when the
    /// server has shutdown (due to keep_running being set to 'false').
    ///
    pub fn process_events(&mut self, events: &mut Events) -> bool {
        self.poll
            .poll(events, self.poll_duration)
            .expect("server event poll failed; cannot recover");

        for msg in events.iter() {
            match msg.token() {
                MESSAGE => {
                    loop {
                        check_ctrlc!(self.keep_running);

                        self.merkle.reset();
                        self.requests.clear();

                        let socket_now_empty = self.collect_requests();

                        if self.requests.is_empty() {
                            break;
                        }

                        self.send_responses();

                        if socket_now_empty {
                            break;
                        }
                    }
                }

                HEALTH_CHECK => {
                    let listener = self.health_listener.as_ref().unwrap();

                    match listener.accept() {
                        Ok((ref mut stream, src_addr)) => {
                            info!("health check from {}", src_addr);
                            self.stats.add_health_check(&src_addr.ip());

                            match stream.write(HTTP_RESPONSE.as_bytes()) {
                                Ok(_) => (),
                                Err(e) => warn!("error writing health check {}", e),
                            };

                            match stream.shutdown(Shutdown::Both) {
                                Ok(_) => (),
                                Err(e) => warn!("error in health check socket shutdown {}", e),
                            }
                        }
                        Err(ref e) if e.kind() == ErrorKind::WouldBlock => {
                            debug!("blocking in TCP health check");
                        }
                        Err(e) => {
                            warn!("unexpected health check error {}", e);
                        }
                    }
                }

                STATUS => {
                    let mut vec: Vec<(&IpAddr, &ClientStatEntry)> = self.stats.iter().collect();
                    vec.sort_by(|lhs, rhs| lhs.1.valid_requests.cmp(&rhs.1.valid_requests));

                    for (addr, counts) in vec {
                        info!(
                            "{:16}: {} valid, {} invalid requests; {} responses ({} sent)",
                            format!("{}", addr), counts.valid_requests, counts.invalid_requests,
                            counts.responses_sent,
                            counts.bytes_sent.file_size(fsopts::BINARY).unwrap()
                        );
                    }

                    info!(
                        "Totals: {} unique clients; {} valid, {} invalid requests; {} responses ({} sent)",
                        self.stats.total_unique_clients(),
                        self.stats.total_valid_requests(), self.stats.total_invalid_requests(),
                        self.stats.total_responses_sent(),
                        self.stats.total_bytes_sent().file_size(fsopts::BINARY).unwrap()
                    );

                    self.timer.set_timeout(self.config.status_interval(), ());
                }

                _ => unreachable!(),
            }
        }
        false
    }

    // Read and process client requests from socket until empty or 'batch_size' number of
    // requests have been read.
    fn collect_requests(&mut self) -> bool {
        for i in 0..self.config.batch_size() {
            match self.socket.recv_from(&mut self.buf) {
                Ok((num_bytes, src_addr)) => {
                    match self.nonce_from_request(&self.buf, num_bytes) {
                        Ok(nonce) => {
                            self.stats.add_valid_request(&src_addr.ip());
                            self.requests.push((Vec::from(nonce), src_addr));
                            self.merkle.push_leaf(nonce);
                        }
                        Err(e) => {
                            self.stats.add_invalid_request(&src_addr.ip());

                            info!(
                                "Invalid request: '{:?}' ({} bytes) from {} (#{} in batch, resp #{})",
                                e, num_bytes, src_addr, i,
                                self.stats.total_responses_sent() + u64::from(i)
                            );
                        }
                    }
                }
                Err(e) => match e.kind() {
                    ErrorKind::WouldBlock => {
                        return true;
                    }
                    _ => {
                        error!("Error receiving from socket: {:?}: {:?}", e.kind(), e);
                        return false;
                    }
                },
            };
        }

        false
    }

    // extract the client's nonce from its request
    fn nonce_from_request<'a>(&self, buf: &'a [u8], num_bytes: usize) -> Result<&'a [u8], Error> {
        if num_bytes < MIN_REQUEST_LENGTH as usize {
            return Err(Error::RequestTooShort);
        }

        let tag_count = &buf[..4];
        let expected_nonc = &buf[8..12];
        let expected_pad = &buf[12..16];

        let tag_count_is_2 = tag_count == [0x02, 0x00, 0x00, 0x00];
        let tag1_is_nonc = expected_nonc == Tag::NONC.wire_value();
        let tag2_is_pad = expected_pad == Tag::PAD.wire_value();

        if tag_count_is_2 && tag1_is_nonc && tag2_is_pad {
            Ok(&buf[0x10..0x50])
        } else {
            Err(Error::InvalidRequest)
        }
    }

    fn send_responses(&mut self) {
        let merkle_root = self.merkle.compute_root();

        // The SREP tag is identical for each response
        let srep = self.online_key.make_srep(SystemTime::now(), &merkle_root);

        for (i, &(ref nonce, ref src_addr)) in self.requests.iter().enumerate() {
            let paths = self.merkle.get_paths(i);
            let resp_msg = {
                let r = self.make_response(&srep, &self.cert_bytes, &paths, i as u32);
                if self.grease.should_add_error() { self.grease.add_errors(&r) } else { r }
            };
            let resp_bytes = resp_msg.encode().unwrap();

            let bytes_sent = self
                .socket
                .send_to(&resp_bytes, &src_addr)
                .expect("send_to failed");

            self.stats.add_response(&src_addr.ip(), bytes_sent);

            info!(
                "Responded {} bytes to {} for '{}..' (#{} in batch, resp #{})",
                bytes_sent,
                src_addr,
                hex::encode(&nonce[0..4]),
                i + 1,
                self.stats.total_responses_sent()
            );
        }
    }

    fn make_response(&self, srep: &RtMessage, cert_bytes: &[u8], path: &[u8], idx: u32) -> RtMessage {
        let mut index = [0; 4];
        (&mut index as &mut [u8])
            .write_u32::<LittleEndian>(idx)
            .unwrap();

        let sig_bytes = srep.get_field(Tag::SIG).unwrap();
        let srep_bytes = srep.get_field(Tag::SREP).unwrap();

        let mut response = RtMessage::new(5);
        response.add_field(Tag::SIG, sig_bytes).unwrap();
        response.add_field(Tag::PATH, path).unwrap();
        response.add_field(Tag::SREP, srep_bytes).unwrap();
        response.add_field(Tag::CERT, cert_bytes).unwrap();
        response.add_field(Tag::INDX, &index).unwrap();

        response
    }
}
<|endoftext|>


<commit_before>extern crate dbus;
use self::dbus::{Connection, Message, MessageType, NameFlag, ReleaseNameReply};
use self::dbus::obj::ObjectPath;

use super::error::DBusError;
use super::target::DBusTarget;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, ObjectPath<'a>>,
    signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_owned(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn add_object(&mut self, path: &str, add_interfaces: fn (&mut ObjectPath<'a>) -> ()) -> Result<&mut Self, Box<Error>> {
        // XXX: Use `.map` when type resolution works better. Currently, `.map` causes the caller
        // type to be set in stone due to eager type resolution and no fluidity in setting it. This
        // causes the type to be too concrete on the caller side which then fails to map to the end
        // result type of `.map` even though `.map` is "transparent" to the error type.
        Result::map(match self.objects.entry(path.to_owned()) {
            Entry::Vacant(v)    => {
                let mut obj = ObjectPath::new(self.conn, path, true);
                try!(obj.set_registered(true));

                // Add interfaces.
                add_interfaces(&mut obj);

                v.insert(obj);

                Ok(())
            },
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_owned()))),
        }, |_| self)
    }

    pub fn remove_object(&mut self, path: &str) -> Result<&mut Self, DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(self),
            None    => Err(DBusError::NoSuchPath(path.to_owned())),
        }
    }

    pub fn connect(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> &mut Self {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };

        self
    }

    pub fn handle_message<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        match m.msg_type() {
            MessageType::Signal     => Some(self._match_signal(m)),
            MessageType::MethodCall => self._call_method(m),
            _                       => Some(m),
        }
    }

    fn _call_method<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        self.objects.iter_mut().fold(Some(m), |opt_m, (_, object)| {
            opt_m.and_then(|mut m| {
                match object.handle_message(&mut m) {
                    None          => Some(m),
                    Some(Ok(()))  => None,
                    Some(Err(())) => {
                        println!("failed to send a reply for {:?}", m);
                        None
                    },
                }
            })
        })
    }

    fn _match_signal<'b>(&self, m: &'b mut Message) -> &'b mut Message {
        let ref signals = self.signals;
        let conn = self.conn;

        DBusTarget::extract(m).and_then(|signal| {
            signals.get(&signal).map(|fs| {
                fs.iter().fold((conn, signal), |(conn, signal), f| {
                    f(&conn, &signal);
                    (conn, signal)
                })
            })
        });

        m
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<commit_msg>server: simplify signal matching<commit_after>extern crate dbus;
use self::dbus::{Connection, Message, MessageType, NameFlag, ReleaseNameReply};
use self::dbus::obj::ObjectPath;

use super::error::DBusError;
use super::target::DBusTarget;

use std::collections::btree_map::{BTreeMap, Entry};
use std::error::Error;

pub struct DBusServer<'a> {
    conn: &'a Connection,
    name: String,

    objects: BTreeMap<String, ObjectPath<'a>>,
    signals: BTreeMap<DBusTarget, Vec<fn (&Connection, &DBusTarget) -> ()>>
}

impl<'a> DBusServer<'a> {
    pub fn new(conn: &'a Connection, name: &str) -> Result<DBusServer<'a>, dbus::Error> {
        try!(conn.register_name(name, NameFlag::DoNotQueue as u32));

        Ok(DBusServer {
            conn: conn,
            name: name.to_owned(),

            objects: BTreeMap::new(),
            signals: BTreeMap::new(),
        })
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn add_object(&mut self, path: &str, add_interfaces: fn (&mut ObjectPath<'a>) -> ()) -> Result<&mut Self, Box<Error>> {
        // XXX: Use `.map` when type resolution works better. Currently, `.map` causes the caller
        // type to be set in stone due to eager type resolution and no fluidity in setting it. This
        // causes the type to be too concrete on the caller side which then fails to map to the end
        // result type of `.map` even though `.map` is "transparent" to the error type.
        Result::map(match self.objects.entry(path.to_owned()) {
            Entry::Vacant(v)    => {
                let mut obj = ObjectPath::new(self.conn, path, true);
                try!(obj.set_registered(true));

                // Add interfaces.
                add_interfaces(&mut obj);

                v.insert(obj);

                Ok(())
            },
            Entry::Occupied(_)  => Err(Box::new(DBusError::PathAlreadyRegistered(path.to_owned()))),
        }, |_| self)
    }

    pub fn remove_object(&mut self, path: &str) -> Result<&mut Self, DBusError> {
        match self.objects.remove(path) {
            Some(_) => Ok(self),
            None    => Err(DBusError::NoSuchPath(path.to_owned())),
        }
    }

    pub fn connect(&mut self, signal: DBusTarget, callback: fn (&Connection, &DBusTarget) -> ()) -> &mut Self {
        match self.signals.entry(signal) {
            Entry::Vacant(v)    => { v.insert(vec![callback]); },
            Entry::Occupied(o)  => o.into_mut().push(callback),
        };

        self
    }

    pub fn handle_message<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        match m.msg_type() {
            MessageType::Signal     => Some(self._match_signal(m)),
            MessageType::MethodCall => self._call_method(m),
            _                       => Some(m),
        }
    }

    fn _call_method<'b>(&mut self, m: &'b mut Message) -> Option<&'b mut Message> {
        self.objects.iter_mut().fold(Some(m), |opt_m, (_, object)| {
            opt_m.and_then(|mut m| {
                match object.handle_message(&mut m) {
                    None          => Some(m),
                    Some(Ok(()))  => None,
                    Some(Err(())) => {
                        println!("failed to send a reply for {:?}", m);
                        None
                    },
                }
            })
        })
    }

    fn _match_signal<'b>(&self, m: &'b mut Message) -> &'b mut Message {
        DBusTarget::extract(m).map(|signal| {
            self.signals.get(&signal).map(|fs| {
                fs.iter().map(|f| {
                    f(&self.conn, &signal);
                })
            });
        });

        m
    }
}

impl<'a> Drop for DBusServer<'a> {
    fn drop(&mut self) {
        let res = self.conn.release_name(&self.name);
        match res {
            Ok(reply) =>
                match reply {
                    ReleaseNameReply::Released    => (),
                    ReleaseNameReply::NonExistent => panic!("internal error: non-existent name {}?!", self.name),
                    ReleaseNameReply::NotOwner    => panic!("internal error: not the owner of {}?!", self.name),
                },
            Err(err) => println!("failed to release {}: {:?}: {:?}", self.name, err.name(), err.message()),
        }
    }
}
<|endoftext|>