<commit_before>use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;
use std::to_num::ToNum;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Vec<u32>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Ok(mut font_file) = File::open("file:/ui/unifont.font") {
            font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:///{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Ok(file) => {
                Some(box Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    file: file,
                    font: font,
                    data: vec![0; (w * h * 4) as usize],
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital://x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let parts: Vec<&str> = path_str.split('/').collect();
                if let Some(x) = parts.get(3) {
                    self.x = x.to_num_signed();
                }
                if let Some(y) = parts.get(4) {
                    self.y = y.to_num_signed();
                }
                if let Some(w) = parts.get(5) {
                    self.w = w.to_num();
                }
                if let Some(h) = parts.get(6) {
                    self.h = h.to_num();
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let offset = y as u32 * self.w + x as u32;
            self.data[offset as usize] = color.data;
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        let w = self.w;
        let h = self.h;
        self.rect(0, 0, w, h, color);
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, color: Color) {
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Poll for an event
    // TODO: clean this up
    pub fn poll(&mut self) -> Option<Event> {
        let mut event = Event::new();
        let event_ptr: *mut Event = &mut event;
        loop {
            match self.file.read(&mut unsafe {
                slice::from_raw_parts_mut(event_ptr as *mut u8, mem::size_of::<Event>())
            }) {
                Ok(0) => thread::yield_now(),
                Ok(_) => return Some(event),
                Err(_) => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.seek(SeekFrom::Start(0));
        self.file.write(&unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8,
                                  self.data.len() * mem::size_of::<u32>())
        });
        return self.file.sync_all().is_ok();
    }

    /// Return a iterator over events
    pub fn event_iter<'a>(&'a mut self) -> EventIter<'a> {
        EventIter { window: self }
    }
}

/// Event iterator
pub struct EventIter<'a> {
    window: &'a mut Window,
}

impl<'a> Iterator for EventIter<'a> {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        self.window.poll()
    }
}
<commit_msg>Allow client connections and slow, but correct, alpha blending in client apps<commit_after>use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;
use std::to_num::ToNum;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Vec<u32>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Ok(mut font_file) = File::open("file:/ui/unifont.font") {
            font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Ok(file) => {
                Some(box Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    file: file,
                    font: font,
                    data: vec![0; (w * h * 4) as usize],
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital://x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let parts: Vec<&str> = path_str.split('/').collect();
                if let Some(x) = parts.get(3) {
                    self.x = x.to_num_signed();
                }
                if let Some(y) = parts.get(4) {
                    self.y = y.to_num_signed();
                }
                if let Some(w) = parts.get(5) {
                    self.w = w.to_num();
                }
                if let Some(h) = parts.get(6) {
                    self.h = h.to_num();
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize];
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        let w = self.w;
        let h = self.h;
        self.rect(0, 0, w, h, color);
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, color: Color) {
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Poll for an event
    // TODO: clean this up
    pub fn poll(&mut self) -> Option<Event> {
        let mut event = Event::new();
        let event_ptr: *mut Event = &mut event;
        loop {
            match self.file.read(&mut unsafe {
                slice::from_raw_parts_mut(event_ptr as *mut u8, mem::size_of::<Event>())
            }) {
                Ok(0) => thread::yield_now(),
                Ok(_) => return Some(event),
                Err(_) => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(&unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8,
                                  self.data.len() * mem::size_of::<u32>())
        }).is_ok()
    }

    /// Return a iterator over events
    pub fn event_iter<'a>(&'a mut self) -> EventIter<'a> {
        EventIter { window: self }
    }
}

/// Event iterator
pub struct EventIter<'a> {
    window: &'a mut Window,
}

impl<'a> Iterator for EventIter<'a> {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        self.window.poll()
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;
use std::to_num::ToNum;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Box<[Color]>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Ok(mut font_file) = File::open("file:/ui/unifont.font") {
            let _ = font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:/{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Ok(file) => {
                Some(box Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    file: file,
                    font: font,
                    data: vec![Color::rgb(0, 0, 0); (w * h * 4) as usize].into_boxed_slice(),
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital://x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let parts: Vec<&str> = path_str.split('/').collect();
                if let Some(x) = parts.get(3) {
                    self.x = x.to_num_signed();
                }
                if let Some(y) = parts.get(4) {
                    self.y = y.to_num_signed();
                }
                if let Some(w) = parts.get(5) {
                    self.w = w.to_num();
                }
                if let Some(h) = parts.get(6) {
                    self.h = h.to_num();
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize].data;
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        for mut d in self.data.iter_mut() {
            *d = color;
        }
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, color: Color) {
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Return a iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => thread::yield_now(),
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }

    /// Poll for an event
    // TODO: Replace with events()
    #[deprecated]
    pub fn poll(&mut self) -> Option<Event> {
        loop {
            let mut event = Event::new();
            match self.file.read(&mut event) {
                Ok(0) => thread::yield_now(),
                Ok(_) => return Some(event),
                Err(_) => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<Color>())
        }).is_ok()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<commit_msg>Fix movement of file manager<commit_after>use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;
use std::to_num::ToNum;

use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// The input scheme
    file: File,
    /// Font file
    font: Vec<u8>,
    /// Window data
    data: Box<[Color]>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Box<Self>> {
        let mut font = Vec::new();
        if let Ok(mut font_file) = File::open("file:/ui/unifont.font") {
            let _ = font_file.read_to_end(&mut font);
        }

        match File::open(&format!("orbital:/{}/{}/{}/{}/{}", x, y, w, h, title)) {
            Ok(file) => {
                Some(box Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    file: file,
                    font: font,
                    data: vec![Color::rgb(0, 0, 0); (w * h * 4) as usize].into_boxed_slice(),
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital:/x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let mut parts = path_str.split('/').skip(1);
                if let Some(x) = parts.next() {
                    self.x = x.to_num_signed();
                }
                if let Some(y) = parts.next() {
                    self.y = y.to_num_signed();
                }
                if let Some(w) = parts.next() {
                    self.w = w.to_num();
                }
                if let Some(h) = parts.next() {
                    self.h = h.to_num();
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize].data;
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < self.font.len() {
                row_data = self.font[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        for mut d in self.data.iter_mut() {
            *d = color;
        }
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, color: Color) {
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Return a iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => thread::yield_now(),
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }

    /// Poll for an event
    // TODO: Replace with events()
    #[deprecated]
    pub fn poll(&mut self) -> Option<Event> {
        loop {
            let mut event = Event::new();
            match self.file.read(&mut event) {
                Ok(0) => thread::yield_now(),
                Ok(_) => return Some(event),
                Err(_) => return None,
            }
        }
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<Color>())
        }).is_ok()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load, wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy};
use types::Cursor;
use std::ptr;
use utils::safe_as_cstring;

#[derive(Debug)]
pub struct XCursorManager {
    manager: *mut wlr_xcursor_manager
}

impl XCursorManager {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager })
            }
        }
    }

    /// returns 0 if the scaled theme was successfully loaded and 1 otherwise
    pub fn load(&self, scale: f32) -> i32 {
        unsafe {
            wlr_xcursor_manager_load(self.manager, scale)
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_ptr = safe_as_cstring(name).as_ptr();
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_ptr, cursor.as_ptr());
        }
    }
}

impl Drop for XCursorManager {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<commit_msg>add xcursor manager size getter<commit_after>use wlroots_sys::{wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_load, wlr_xcursor_manager_set_cursor_image, wlr_xcursor_manager_destroy};
use types::Cursor;
use std::ptr;
use utils::safe_as_cstring;

#[derive(Debug)]
pub struct XCursorManager {
    manager: *mut wlr_xcursor_manager
}

impl XCursorManager {
    pub fn create<T: Into<Option<String>>>(name: T, size: u32) -> Option<Self> {
        unsafe {
            let name_str = name.into().map(safe_as_cstring);
            let name_ptr = name_str.map(|s| s.as_ptr()).unwrap_or(ptr::null_mut());
            let manager = wlr_xcursor_manager_create(name_ptr, size);
            if manager.is_null() {
                None
            } else {
                Some(XCursorManager { manager })
            }
        }
    }

    pub fn size(&self) -> u32 {
        unsafe { (*self.manager).size }
    }

    /// returns 0 if the scaled theme was successfully loaded and 1 otherwise
    pub fn load(&self, scale: f32) -> i32 {
        unsafe {
            wlr_xcursor_manager_load(self.manager, scale)
        }
    }

    pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) {
        let name_ptr = safe_as_cstring(name).as_ptr();
        unsafe {
            wlr_xcursor_manager_set_cursor_image(self.manager, name_ptr, cursor.as_ptr());
        }
    }
}

impl Drop for XCursorManager {
    fn drop(&mut self) {
        unsafe { wlr_xcursor_manager_destroy(self.manager) }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

/// This client's writer channel
static mut writer_tx: *mut Sender<Vec<u8>> = 0 as *mut Sender<Vec<u8>>;

/// This client's kill channel
static mut kill_tx: *mut Sender<()> = 0 as *mut Sender<()>;

#[no_mangle]
pub extern "C" fn hydrogen_start(address: *const c_char,
    data_handler: extern fn(*const c_char),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    // TODO - adjust this to accept a log level adjustable by whoever is running
    // the application
    super::init();

    trace!("Rust - start()");

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            error!("Invalid host address");
            return -1 as c_int;
        }
    };
    trace!("Address: ");

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    unsafe { kill_tx = &mut k_tx.clone(); }

    // Writer thread's channel
    let (w_tx, writer_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    unsafe { writer_tx = &mut w_tx.clone(); }

    debug!("Attempting connect to: {}", host_address);

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        error!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    debug!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);
    let r_client = client.clone();
    let w_client = client.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, data_handler)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(writer_rx, w_client)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            error!("Error on kill channel: {}", e);
            on_disconnect_handler();
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn hydrogen_write(buffer: *const c_char) -> c_int {
    trace!("Rust.write");

    let mut buf_as_cstr;
    unsafe {
        buf_as_cstr = CStr::from_ptr(buffer);
    }
    let buf_as_slice = buf_as_cstr.to_bytes();

    let mut n_buffer = Vec::<u8>::with_capacity(buf_as_slice.len());
    for byte in buf_as_slice.iter() {
        n_buffer.push(*byte);
    }

    unsafe {
        match (*writer_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                warn!("Error sending buffer: {}", e);
                let _ = (*kill_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream, handler: extern fn(*const c_char)) {
    trace!("Rust.reader_thread started");

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        handler(c_buffer.as_ptr());
                    }).unwrap();
            }
            Err(e) => {
                error!("Error: {}", e);
                break;
            }
        };
    }
    debug!("Rust.reader_thread finished");
    unsafe { let _ = (*kill_tx).send(()); }
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream) {
    trace!("Rust.writer_thread started");

    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        error!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                error!("Error: {}", e);
                break;
            }
        };
    }

    debug!("Rust.writer_thread finished");
    unsafe { let _ = (*kill_tx).send(()); }
}

/// Drops the current connection and kills all current threads
#[no_mangle]
pub extern "C" fn hydrogen_kill() {
    unsafe { let _ = (*kill_tx).send(()); }
}
<commit_msg>Client logging tests<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

/// This client's writer channel
static mut writer_tx: *mut Sender<Vec<u8>> = 0 as *mut Sender<Vec<u8>>;

/// This client's kill channel
static mut kill_tx: *mut Sender<()> = 0 as *mut Sender<()>;

#[no_mangle]
pub extern "C" fn hydrogen_start(address: *const c_char,
    data_handler: extern fn(*const c_char),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    // TODO - adjust this to accept a log level adjustable by whoever is running
    // the application
    super::init();

    println!("Test from Rust");

    trace!("Rust - start()");

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            error!("Invalid host address");
            return -1 as c_int;
        }
    };
    trace!("Address: ");

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    unsafe { kill_tx = &mut k_tx.clone(); }

    // Writer thread's channel
    let (w_tx, writer_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    unsafe { writer_tx = &mut w_tx.clone(); }

    debug!("Attempting connect to: {}", host_address);

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        error!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    debug!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);
    let r_client = client.clone();
    let w_client = client.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, data_handler)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(writer_rx, w_client)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            error!("Error on kill channel: {}", e);
            on_disconnect_handler();
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn hydrogen_write(buffer: *const c_char) -> c_int {
    trace!("Rust.write");

    let mut buf_as_cstr;
    unsafe {
        buf_as_cstr = CStr::from_ptr(buffer);
    }
    let buf_as_slice = buf_as_cstr.to_bytes();

    let mut n_buffer = Vec::<u8>::with_capacity(buf_as_slice.len());
    for byte in buf_as_slice.iter() {
        n_buffer.push(*byte);
    }

    unsafe {
        match (*writer_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                warn!("Error sending buffer: {}", e);
                let _ = (*kill_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream, handler: extern fn(*const c_char)) {
    trace!("Rust.reader_thread started");

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        handler(c_buffer.as_ptr());
                    }).unwrap();
            }
            Err(e) => {
                error!("Error: {}", e);
                break;
            }
        };
    }
    debug!("Rust.reader_thread finished");
    unsafe { let _ = (*kill_tx).send(()); }
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream) {
    trace!("Rust.writer_thread started");

    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        error!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                error!("Error: {}", e);
                break;
            }
        };
    }

    debug!("Rust.writer_thread finished");
    unsafe { let _ = (*kill_tx).send(()); }
}

/// Drops the current connection and kills all current threads
#[no_mangle]
pub extern "C" fn hydrogen_kill() {
    unsafe { let _ = (*kill_tx).send(()); }
}
<|endoftext|>


<commit_before>use stb_image::*;
use stb_image::bindgen::*;
use libc::types::os::arch::c95::c_int;
use ptr::{is_null, to_unsafe_ptr};
use str::as_c_str;
use vec::as_imm_buf;
use vec::raw::from_buf_raw;

pub struct Image {
    width: uint,
    height: uint,
    depth: uint,
    data: ~[u8],
}

pub fn new_image(width: uint, height: uint, depth: uint, data: ~[u8]) -> Image {
    Image {
        width : width,
        height : height,
        depth : depth,
        data : move data,
    }
}

pub fn load(path: ~str) -> Option<Image> unsafe {
    let force_depth = 4;
    load_with_depth(move path, force_depth)
}

pub fn load_with_depth(path: ~str, force_depth: uint) -> Option<Image> unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let buffer = as_c_str(path, |bytes| {
            stbi_load(bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                      to_unsafe_ptr(&depth), force_depth as c_int)
        });

        if is_null(buffer) {
            None
        } else {
            // FIXME: Shouldn't copy; instead we should use a sendable resource. They
            // aren't particularly safe yet though.
            let data = from_buf_raw(buffer, ((width * height) as uint) * force_depth);
            libc::free(buffer as *c_void);
            Some(new_image(width as uint, height as uint, force_depth, move data))
        }
    }
}

pub fn load_from_memory(buffer: &[u8]) -> Option<Image> unsafe {
        let force_depth = 4;
        load_from_memory_with_depth(buffer, force_depth)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint) -> Option<Image> unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let buffer = as_imm_buf(buffer, |bytes, len| {
            stbi_load_from_memory(bytes, len as c_int, to_unsafe_ptr(&width),
                                  to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                                  force_depth as c_int)
        });

        if is_null(buffer) {
            None
        } else {
            // FIXME: Shouldn't copy; instead we should use a sendable resource. They
            // aren't particularly safe yet though.
            let data = from_buf_raw(buffer, ((width * height) as uint) * force_depth);
            libc::free(buffer as *c_void);
            Some(new_image(width as uint, height as uint, force_depth, move data))
        }
    }
}
<commit_msg>HDR image loading<commit_after>use stb_image::*;
use stb_image::bindgen::*;
use libc::types::os::arch::c95::c_int;
use ptr::{is_null, to_unsafe_ptr};
use str::as_c_str;
use vec::as_imm_buf;
use vec::raw::from_buf_raw;

pub struct Image<T> {
    width   : uint,
    height  : uint,
    depth   : uint,
    data    : ~[T],
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: ~[T]) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : move data,
    }
}

enum LoadResult {
    Error,
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

pub fn load(path: ~str) -> LoadResult unsafe {
    let force_depth = 0;
    load_with_depth(move path, force_depth, false)
}

priv fn load_internal<T>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> unsafe   {
    // FIXME: Shouldn't copy; instead we should use a sendable resource. They
    // aren't particularly safe yet though.
    let data = from_buf_raw(buf, (w * h * d) as uint);
    libc::free(buf as *c_void);
    Image::<T>{
        width   : w as uint,
        height  : h as uint,
        depth   : d as uint,
        data    : data}
}

pub fn load_with_depth(path: ~str, force_depth: uint, convert_hdr:bool) -> LoadResult unsafe {
    do task::unkillable {
        let mut width   = 0 as c_int;
        let mut height  = 0 as c_int;
        let mut depth   = 0 as c_int;
        as_c_str(path, |bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(
                    bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                    to_unsafe_ptr(&depth), force_depth as c_int);
                if is_null(buffer) {
                    Error
                } else {
                    ImageF32( load_internal(buffer,width,height,depth) )
                }
            }else   {
                let buffer = stbi_load(
                    bytes, to_unsafe_ptr(&width), to_unsafe_ptr(&height),
                    to_unsafe_ptr(&depth), force_depth as c_int);
                if is_null(buffer) {
                    Error
                } else {
                    ImageU8( load_internal(buffer,width,height,depth) )
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult unsafe {
        let force_depth = 0;
        load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult unsafe {
    do task::unkillable {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        as_imm_buf(buffer, |bytes, len| {
            if !convert_hdr && stbi_is_hdr_from_memory(bytes,len as c_int)!=0   {
                let buffer = stbi_loadf_from_memory(
                    bytes, len as c_int, to_unsafe_ptr(&width),
                    to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                    force_depth as c_int);
                if is_null(buffer) {
                    Error
                } else {
                    ImageF32( load_internal(buffer,width,height,depth) )
                }
            }else   {
                let buffer = stbi_load_from_memory(
                    bytes, len as c_int, to_unsafe_ptr(&width),
                    to_unsafe_ptr(&height), to_unsafe_ptr(&depth),
                    force_depth as c_int);
                if is_null(buffer) {
                    Error
                } else {
                    ImageU8( load_internal(buffer,width,height,depth) )
                }
            }
        })
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;
use rustbox::*;
use screen::common::*;
use utility::string::*;
use model::ShowItem;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show { rustbox: &rustbox }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        print_header(&self.rustbox,
                     self.rustbox.width(),
                     &format!("{} - {}", item.title, title));
        print_body(&self.rustbox,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &item);
    }
    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: &str) {
    let title_len = jks_len(text);
    let padding = (if width >= title_len {
        width - title_len
    } else {
        0
    }) / 2;

    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              item: &ShowItem) {

    for (i, reply) in item.replies.iter().take(1).enumerate() {
        rustbox.print(0,
                      i + offset_y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &format!("{}", reply.content));
    }
}
<commit_msg>show - print seperator with author name<commit_after>extern crate rustbox;
use rustbox::*;
use screen::common::*;
use utility::string::*;
use model::ShowItem;

pub struct Show<'a> {
    rustbox: &'a rustbox::RustBox,
}

impl<'a> Show<'a> {
    pub fn new(rustbox: &'a rustbox::RustBox) -> Self {
        Show { rustbox: &rustbox }
    }
    pub fn print(&mut self, title: &str, item: &ShowItem) {

        print_header(&self.rustbox,
                     self.rustbox.width(),
                     &format!("{} - {}", item.title, title));
        print_body(&self.rustbox,
                   self.body_width(),
                   2,
                   self.body_height(),
                   &item);
    }
    pub fn body_height(&self) -> usize {
        if self.rustbox.height() >= 3 {
            self.rustbox.height() - 3
        } else {
            0
        }
    }

    pub fn body_width(&self) -> usize {
        if self.rustbox.width() >= 2 {
            self.rustbox.width() - 2
        } else {
            0
        }
    }
}

fn print_header(rustbox: &rustbox::RustBox, width: usize, text: &str) {
    let title_len = jks_len(text);
    let padding = (if width >= title_len {
        width - title_len
    } else {
        0
    }) / 2;

    let header_bottom = (0..width).map(|_| "─").collect::<Vec<_>>().join("");

    clearline(&rustbox, width, 0, 0);
    rustbox.print(padding,
                  0,
                  rustbox::RB_BOLD,
                  Color::White,
                  Color::Black,
                  text);
    rustbox.print(0,
                  1,
                  rustbox::RB_BOLD,
                  Color::Yellow,
                  Color::Black,
                  &header_bottom);
}

fn print_body(rustbox: &rustbox::RustBox,
              width: usize,
              offset_y: usize,
              rows: usize,
              item: &ShowItem) {

    let mut y = offset_y;
    let replier_max_width = 14;

    let separator_width = if rustbox.width() >= 4 {
        rustbox.width() - 4
    } else {
        0
    };
    let separator_padding_width = if rustbox.width() > separator_width {
        rustbox.width() - separator_width
    } else {
        0
    } / 2;

    let separator_padding = (0..separator_padding_width).map(|_| " ").collect::<Vec<_>>().join("");

    let separator_bottom = make_separator_bottom(separator_width, &separator_padding);

    for (i, reply) in item.replies.iter().take(rows).enumerate() {
        let contents: Vec<&str> = reply.content.split("\n").collect();

        let mut m = 0;

        for (j, content) in contents.iter().enumerate() {
            rustbox.print(0,
                          j + y,
                          rustbox::RB_NORMAL,
                          Color::White,
                          Color::Black,
                          &format!(" {}", content));
            m += 1;
        }
        let replier_name = reply.username.clone();
        let separator_top = make_separator_top(separator_width,
                                               &separator_padding,
                                               replier_max_width,
                                               &replier_name);

        rustbox.print(0,
                      m + y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &separator_top);
        m += 1;

        rustbox.print(0,
                      m + y,
                      rustbox::RB_NORMAL,
                      Color::White,
                      Color::Black,
                      &separator_bottom);
        m += 1;
        y += m;
    }
}

fn make_separator_top(separator_width: usize,
                      separator_padding: &str,
                      replier_max_width: usize,
                      replier_name: &str)
                      -> String {
    let replier_name_len = jks_len(&replier_name);
    let replier_name_spacing_width = replier_max_width - replier_name_len;
    let is_replier_name_spacing_width_odd = replier_name_spacing_width & 1 == 1;
    let replier_name_right_spacing_width = replier_name_spacing_width / 2;
    let replier_name_left_spacing_width = if is_replier_name_spacing_width_odd {
        replier_name_right_spacing_width + 1
    } else {
        replier_name_right_spacing_width
    };

    let replier_name_left_spacing = (0..replier_name_left_spacing_width)
                                        .map(|_| "─")
                                        .collect::<Vec<_>>()
                                        .join("");

    let replier_name_right_spacing = (0..replier_name_right_spacing_width)
                                         .map(|_| "─")
                                         .collect::<Vec<_>>()
                                         .join("");

    let separator_replier = format!("{}{}{}{}{}",
                                    "╭",
                                    replier_name_left_spacing,
                                    replier_name,
                                    replier_name_right_spacing,
                                    "╮");
    let separator_replier_width = jks_len(&separator_replier);

    let separator_top_middle_width = if separator_width > separator_replier_width {
        separator_width - separator_replier_width
    } else {
        0
    };
    let separator_top_middle = (0..separator_top_middle_width)
                                   .map(|_| " ")
                                   .collect::<Vec<_>>()
                                   .join("");

    let separator_top = format!("{}{}{}{}",
                                separator_padding,
                                separator_top_middle,
                                separator_replier,
                                separator_padding);
    return separator_top;
}
fn make_separator_bottom(separator_width: usize, separator_padding: &str) -> String {
    let style_box_width = 1;
    let separator_bottom_middle_width = if separator_width > style_box_width {
        separator_width - style_box_width
    } else {
        0
    };
    let separator_bottom_middle = (0..separator_bottom_middle_width)
                                      .map(|_| "─")
                                      .collect::<Vec<_>>()
                                      .join("");
    let separator_bottom = format!("{}{}{}{}",
                                   separator_padding,
                                   separator_bottom_middle,
                                   "╯",
                                   separator_padding);
    return separator_bottom;
}
<|endoftext|>


<commit_before>//! Convenient Response utils used internally

use tokio_minihttp::Response;
use cors;

pub fn method_not_allowed() -> Response {
	let mut response = Response::new();
	response
		.status_code(405, "Method Not Allowed")
		.header("Content-Type", "text/plain")
		.body("Used HTTP Method is not allowed. POST or OPTIONS is required.\n");
	response
}

pub fn invalid_host() -> Response {
	let mut response = Response::new();
	response
		.status_code(403, "Forbidden")
		.header("Content-Type", "text/plain")
		.body("Provided Host header is not whitelisted.\n");
	response
}

pub fn invalid_content_type() -> Response {
	let mut response = Response::new();
	response
		.status_code(415, "Unsupported Media Type")
		.header("Content-Type", "text/plain")
		.body("Supplied content type is not allowed. Content-Type: application/json is required.\n");
	response
}

pub fn new(body: &str, cors: Option<cors::AccessControlAllowOrigin>) -> Response {
	let mut response = Response::new();
	response
		.header("Content-Type", "application/json")
		.body(body);

	if let Some(cors) = cors {
		response
			.header("Access-Control-Allow-Methods", "OPTIONS, POST")
			.header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept")
			.header("Access-Control-Allow-Origin", match cors {
				cors::AccessControlAllowOrigin::Null => "null",
				cors::AccessControlAllowOrigin::Any => "*",
				cors::AccessControlAllowOrigin::Value(ref val) => val,
			})
			.header("Vary", "Origin");
	}
	response
}
<commit_msg>Custom Server header<commit_after>//! Convenient Response utils used internally

use tokio_minihttp::Response;
use cors;

const SERVER: &'static str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));

pub fn method_not_allowed() -> Response {
	let mut response = Response::new();
	response
		.status_code(405, "Method Not Allowed")
		.server(SERVER)
		.header("Content-Type", "text/plain")
		.body("Used HTTP Method is not allowed. POST or OPTIONS is required.\n");
	response
}

pub fn invalid_host() -> Response {
	let mut response = Response::new();
	response
		.status_code(403, "Forbidden")
		.server(SERVER)
		.header("Content-Type", "text/plain")
		.body("Provided Host header is not whitelisted.\n");
	response
}

pub fn invalid_content_type() -> Response {
	let mut response = Response::new();
	response
		.status_code(415, "Unsupported Media Type")
		.server(SERVER)
		.header("Content-Type", "text/plain")
		.body("Supplied content type is not allowed. Content-Type: application/json is required.\n");
	response
}

pub fn new(body: &str, cors: Option<cors::AccessControlAllowOrigin>) -> Response {
	let mut response = Response::new();
	response
		.header("Content-Type", "application/json")
		.server(SERVER)
		.body(body);

	if let Some(cors) = cors {
		response
			.header("Access-Control-Allow-Methods", "OPTIONS, POST")
			.header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept")
			.header("Access-Control-Allow-Origin", match cors {
				cors::AccessControlAllowOrigin::Null => "null",
				cors::AccessControlAllowOrigin::Any => "*",
				cors::AccessControlAllowOrigin::Value(ref val) => val,
			})
			.header("Vary", "Origin");
	}
	response
}
<|endoftext|>


<commit_before>extern crate bitflags;

extern crate dbus_bytestream;
use self::dbus_bytestream::connection;

use super::error::Error;
use super::message::Message;
use super::value::{BasicValue, Value};

pub struct Connection {
    conn: connection::Connection,
}

bitflags! {
    pub flags RequestNameFlags: u32 {
        const ALLOW_REPLACEMENT = 0x1,
        const REPLACE_EXISTING  = 0x2,
        const DO_NOT_QUEUE      = 0x4,
    }
}

pub enum RequestNameReply {
    PrimaryOwner,
    InQueue,
    Exists,
    AlreadyOwner,
}

pub enum ReleaseNameReply {
    Released,
    NonExistent,
    NotOwner,
}

pub struct Messages<'a> {
    conn: &'a connection::Connection,
}

impl Connection {
    pub fn session_new() -> Result<Connection, Error> {
        Ok(Connection {
            conn: try!(connection::Connection::connect_session()),
        })
    }

    pub fn system_new() -> Result<Connection, Error> {
        Ok(Connection {
            conn: try!(connection::Connection::connect_system()),
        })
    }

    pub fn request_name(&self, name: &str, flags: RequestNameFlags) -> Result<RequestNameReply, Error> {
        let msg = Message::new_method_call(
                "org.freedesktop.DBus",
                "/org/freedesktop/DBus",
                "org.freedesktop.DBus",
                "RequestName")
            .add_argument(&name)
            .add_argument(&flags.bits);
        if let Some(mut results) = try!(self.conn.call_sync(msg.extract())) {
            if let Some(Value::BasicValue(BasicValue::Uint32(r))) = results.pop() {
                match r {
                    1 => Ok(RequestNameReply::PrimaryOwner),
                    2 => Ok(RequestNameReply::InQueue),
                    3 => Ok(RequestNameReply::Exists),
                    4 => Ok(RequestNameReply::AlreadyOwner),
                    _ => Err(Error::InvalidReply(format!("RequestName: invalid response {}", r))),
                }
            } else {
                return Err(Error::InvalidReply("RequestName: invalid response".to_owned()));
            }
        } else {
            return Err(Error::InvalidReply("RequestName: no response".to_owned()));
        }
    }

    pub fn release_name(&self, name: &str) -> Result<ReleaseNameReply, Error> {
        let msg = Message::new_method_call(
                "org.freedesktop.DBus",
                "/org/freedesktop/DBus",
                "org.freedesktop.DBus",
                "ReleaseName")
            .add_argument(&name);
        if let Some(mut results) = try!(self.conn.call_sync(msg.extract())) {
            if let Some(Value::BasicValue(BasicValue::Uint32(r))) = results.pop() {
                match r {
                    1 => Ok(ReleaseNameReply::Released),
                    2 => Ok(ReleaseNameReply::NonExistent),
                    3 => Ok(ReleaseNameReply::NotOwner),
                    _ => Err(Error::InvalidReply(format!("ReleaseName: invalid response {}", r))),
                }
            } else {
                return Err(Error::InvalidReply("ReleaseName: invalid response".to_owned()));
            }
        } else {
            return Err(Error::InvalidReply("ReleaseName: no response".to_owned()));
        }
    }

    pub fn add_match(&self, match_rule: &str) -> Result<(), Error> {
        let msg = Message::new_method_call(
                "org.freedesktop.DBus",
                "/org/freedesktop/DBus",
                "org.freedesktop.DBus",
                "AddMatch")
            .add_argument(&match_rule);
        try!(self.conn.call_sync(msg.extract()));
        Ok(())
    }

    pub fn send(&self, msg: Message) -> Result<u32, Error> {
        Ok(try!(self.conn.send(msg.extract())))
    }

    pub fn iter(&self) -> Messages {
        Messages {
            conn: &self.conn,
        }
    }
}

impl<'a> Iterator for Messages<'a> {
    type Item = Message;

    fn next(&mut self) -> Option<Self::Item> {
        let res = self.conn.read_msg();
        match res {
            Ok(message) => {
                let dbus_message = Message::new(message);
                if dbus_message.should_handle() {
                    Some(dbus_message)
                } else {
                    None
                }
            },
            Err(_)      => None,
        }
    }
}
<commit_msg>connection: add traits to name request enums<commit_after>extern crate bitflags;

extern crate dbus_bytestream;
use self::dbus_bytestream::connection;

use super::error::Error;
use super::message::Message;
use super::value::{BasicValue, Value};

pub struct Connection {
    conn: connection::Connection,
}

bitflags! {
    pub flags RequestNameFlags: u32 {
        const ALLOW_REPLACEMENT = 0x1,
        const REPLACE_EXISTING  = 0x2,
        const DO_NOT_QUEUE      = 0x4,
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum RequestNameReply {
    PrimaryOwner,
    InQueue,
    Exists,
    AlreadyOwner,
}

#[derive(Debug, PartialEq, Eq)]
pub enum ReleaseNameReply {
    Released,
    NonExistent,
    NotOwner,
}

pub struct Messages<'a> {
    conn: &'a connection::Connection,
}

impl Connection {
    pub fn session_new() -> Result<Connection, Error> {
        Ok(Connection {
            conn: try!(connection::Connection::connect_session()),
        })
    }

    pub fn system_new() -> Result<Connection, Error> {
        Ok(Connection {
            conn: try!(connection::Connection::connect_system()),
        })
    }

    pub fn request_name(&self, name: &str, flags: RequestNameFlags) -> Result<RequestNameReply, Error> {
        let msg = Message::new_method_call(
                "org.freedesktop.DBus",
                "/org/freedesktop/DBus",
                "org.freedesktop.DBus",
                "RequestName")
            .add_argument(&name)
            .add_argument(&flags.bits);
        if let Some(mut results) = try!(self.conn.call_sync(msg.extract())) {
            if let Some(Value::BasicValue(BasicValue::Uint32(r))) = results.pop() {
                match r {
                    1 => Ok(RequestNameReply::PrimaryOwner),
                    2 => Ok(RequestNameReply::InQueue),
                    3 => Ok(RequestNameReply::Exists),
                    4 => Ok(RequestNameReply::AlreadyOwner),
                    _ => Err(Error::InvalidReply(format!("RequestName: invalid response {}", r))),
                }
            } else {
                return Err(Error::InvalidReply("RequestName: invalid response".to_owned()));
            }
        } else {
            return Err(Error::InvalidReply("RequestName: no response".to_owned()));
        }
    }

    pub fn release_name(&self, name: &str) -> Result<ReleaseNameReply, Error> {
        let msg = Message::new_method_call(
                "org.freedesktop.DBus",
                "/org/freedesktop/DBus",
                "org.freedesktop.DBus",
                "ReleaseName")
            .add_argument(&name);
        if let Some(mut results) = try!(self.conn.call_sync(msg.extract())) {
            if let Some(Value::BasicValue(BasicValue::Uint32(r))) = results.pop() {
                match r {
                    1 => Ok(ReleaseNameReply::Released),
                    2 => Ok(ReleaseNameReply::NonExistent),
                    3 => Ok(ReleaseNameReply::NotOwner),
                    _ => Err(Error::InvalidReply(format!("ReleaseName: invalid response {}", r))),
                }
            } else {
                return Err(Error::InvalidReply("ReleaseName: invalid response".to_owned()));
            }
        } else {
            return Err(Error::InvalidReply("ReleaseName: no response".to_owned()));
        }
    }

    pub fn add_match(&self, match_rule: &str) -> Result<(), Error> {
        let msg = Message::new_method_call(
                "org.freedesktop.DBus",
                "/org/freedesktop/DBus",
                "org.freedesktop.DBus",
                "AddMatch")
            .add_argument(&match_rule);
        try!(self.conn.call_sync(msg.extract()));
        Ok(())
    }

    pub fn send(&self, msg: Message) -> Result<u32, Error> {
        Ok(try!(self.conn.send(msg.extract())))
    }

    pub fn iter(&self) -> Messages {
        Messages {
            conn: &self.conn,
        }
    }
}

impl<'a> Iterator for Messages<'a> {
    type Item = Message;

    fn next(&mut self) -> Option<Self::Item> {
        let res = self.conn.read_msg();
        match res {
            Ok(message) => {
                let dbus_message = Message::new(message);
                if dbus_message.should_handle() {
                    Some(dbus_message)
                } else {
                    None
                }
            },
            Err(_)      => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File as FSFile;
use std::ops::Deref;
use std::io::Write;
use std::io::Read;

pub mod path;
pub mod file;
pub mod parser;
pub mod json;

use module::Module;
use runtime::Runtime;
use storage::file::File;
use storage::file::id::FileID;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use storage::parser::{FileHeaderParser, Parser, ParserError};
use storage::file::header::data::FileHeaderData;

type Cache = HashMap<FileID, Rc<RefCell<File>>>;

pub struct Store {
    storepath: String,
    cache : RefCell<Cache>,
}

impl Store {

    pub fn new(storepath: String) -> Store {
        Store {
            storepath: storepath,
            cache: RefCell::new(HashMap::new()),
        }
    }

    fn put_in_cache(&self, f: File) -> FileID {
        let res = f.id().clone();
        self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f)));
        res
    }

    pub fn load_in_cache<HP>(&self, m: &Module, parser: &Parser<HP>, id: FileID)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        let idstr : String = id.clone().into();
        let path = format!("{}/{}-{}.imag", self.storepath, m.name(), idstr);
        let mut string = String::new();

        FSFile::open(&path).map(|mut file| {
            file.read_to_string(&mut string)
                .map_err(|e| error!("Failed reading file: '{}'", path));
        });

        parser.read(string).map(|(header, data)| {
            self.new_file_from_parser_result(m, id.clone(), header, data);
        });

        self.load(&id)
    }

    pub fn new_file(&self, module: &Module)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: String::from(""),
            id: self.get_new_file_id(),
        };

        debug!("Create new File object: {:?}", &f);
        self.put_in_cache(f)
    }

    pub fn new_file_from_parser_result(&self,
                                       module: &Module,
                                       id: FileID,
                                       header: FileHeaderData,
                                       data: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn new_file_with_header(&self,
                                module: &Module,
                                h: FileHeaderData)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: String::from(""),
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn new_file_with_data(&self, module: &Module, d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn new_file_with_content(&self,
                                 module: &Module,
                                 h: FileHeaderData,
                                 d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn persist<HP>(&self,
                       p: &Parser<HP>,
                       f: Rc<RefCell<File>>) -> bool
        where HP: FileHeaderParser
    {
        let file = f.deref().borrow();
        let text = p.write(file.contents());
        if text.is_err() {
            error!("Error: {}", text.err().unwrap());
            return false;
        }

        let path = {
            let ids : String = file.id().clone().into();
            format!("{}/{}-{}.imag", self.storepath, file.owning_module_name, ids)
        };

        self.ensure_store_path_exists();

        FSFile::create(&path).map(|mut fsfile| {
            fsfile.write_all(&text.unwrap().clone().into_bytes()[..])
        }).map_err(|writeerr|  {
            debug!("Could not create file at '{}'", path);
        }).and(Ok(true)).unwrap()
    }

    fn ensure_store_path_exists(&self) {
        use std::fs::create_dir_all;
        use std::process::exit;

        create_dir_all(&self.storepath).unwrap_or_else(|e| {
            error!("Could not create store: '{}'", self.storepath);
            error!("Error                 : '{}'", e);
            error!("Killing myself now");
            exit(1);
        })
    }

    pub fn load(&self, id: &FileID) -> Option<Rc<RefCell<File>>> {
        debug!("Loading '{:?}'", id);
        self.cache.borrow().get(id).cloned()
    }

    pub fn load_by_hash<HP>(&self,
                            m: &Module,
                            parser: &Parser<HP>,
                            hash: FileHash)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        macro_rules! try_some {
            ($expr:expr) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return ::std::option::Option::None,
            });

            ($expr:expr => return) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return,
            })
        }

        use glob::{glob, Paths, PatternError};

        let hashstr : String = hash.into();
        let globstr = format!("{}/*-{}.imag", self.storepath, hashstr);
        debug!("glob({})", globstr);

        let globs = glob(&globstr[..]);
        if globs.is_err() {
            return None;
        }

        let path = globs.unwrap().last();
        debug!("path = {:?}", path);

        let pathbuf = try_some!(path);
        if pathbuf.is_err() { return None; }

        let pathbuf_un  = pathbuf.unwrap();
        let filename    = pathbuf_un.file_name();
        let s           = try_some!(filename).to_str();
        let string      = String::from(try_some!(s));
        let id          = try_some!(FileID::parse(&string));

        debug!("Loaded ID = '{:?}'", id);

        self.load_in_cache(m, parser, id)
            .map(|file| {
                debug!("Loaded File = '{:?}'", file);
                Some(file)
            }).unwrap_or(None)
    }

    pub fn remove(&self, id: FileID) -> bool {
        use std::fs::remove_file;

        self.cache
            .borrow_mut()
            .remove(&id)
            .map(|file| {
                let idstr : String = id.into();
                let path = format!("{}/{}-{}.imag",
                                   self.storepath,
                                   file.deref().borrow().owner_name(),
                                   idstr);
                debug!("Removing file NOW: '{}'", path);
                remove_file(path).is_ok()
            })
            .unwrap_or(false)
    }

    pub fn load_for_module<HP>(&self, m: &Module, parser: &Parser<HP>)
        -> Vec<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        use glob::{glob, Paths, PatternError};

        let globstr = format!("{}/{}-*.imag", self.storepath, m.name());
        let mut res = vec![];

        glob(&globstr[..]).map(|paths| {
            for path in paths {
                if let Ok(pathbuf) = path {
                    let fname = pathbuf.file_name().and_then(|s| s.to_str());
                    fname.map(|s| {
                        FileID::parse(&String::from(s)).map(|id| {
                            self.load_in_cache(m, parser, id).map(|file| {
                                res.push(file);
                            })
                        });
                    });
                }
            }
        });
        res
    }

    fn get_new_file_id(&self) -> FileID {
        use uuid::Uuid;
        let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
        FileID::new(FileIDType::UUID, hash)
    }

}
<commit_msg>Add debug output to Store::load_in_cache()<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fs::File as FSFile;
use std::ops::Deref;
use std::io::Write;
use std::io::Read;

pub mod path;
pub mod file;
pub mod parser;
pub mod json;

use module::Module;
use runtime::Runtime;
use storage::file::File;
use storage::file::id::FileID;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use storage::parser::{FileHeaderParser, Parser, ParserError};
use storage::file::header::data::FileHeaderData;

type Cache = HashMap<FileID, Rc<RefCell<File>>>;

pub struct Store {
    storepath: String,
    cache : RefCell<Cache>,
}

impl Store {

    pub fn new(storepath: String) -> Store {
        Store {
            storepath: storepath,
            cache: RefCell::new(HashMap::new()),
        }
    }

    fn put_in_cache(&self, f: File) -> FileID {
        let res = f.id().clone();
        self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f)));
        res
    }

    pub fn load_in_cache<HP>(&self, m: &Module, parser: &Parser<HP>, id: FileID)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        let idstr : String = id.clone().into();
        let path = format!("{}/{}-{}.imag", self.storepath, m.name(), idstr);
        debug!("Loading path = '{}'", path);
        let mut string = String::new();

        FSFile::open(&path).map(|mut file| {
            file.read_to_string(&mut string)
                .map_err(|e| error!("Failed reading file: '{}'", path));
        });

        parser.read(string).map(|(header, data)| {
            self.new_file_from_parser_result(m, id.clone(), header, data);
        });

        self.load(&id)
    }

    pub fn new_file(&self, module: &Module)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: String::from(""),
            id: self.get_new_file_id(),
        };

        debug!("Create new File object: {:?}", &f);
        self.put_in_cache(f)
    }

    pub fn new_file_from_parser_result(&self,
                                       module: &Module,
                                       id: FileID,
                                       header: FileHeaderData,
                                       data: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn new_file_with_header(&self,
                                module: &Module,
                                h: FileHeaderData)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: String::from(""),
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn new_file_with_data(&self, module: &Module, d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: FileHeaderData::Null,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn new_file_with_content(&self,
                                 module: &Module,
                                 h: FileHeaderData,
                                 d: String)
        -> FileID
    {
        let f = File {
            owning_module_name: module.name(),
            header: h,
            data: d,
            id: self.get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        self.put_in_cache(f)
    }

    pub fn persist<HP>(&self,
                       p: &Parser<HP>,
                       f: Rc<RefCell<File>>) -> bool
        where HP: FileHeaderParser
    {
        let file = f.deref().borrow();
        let text = p.write(file.contents());
        if text.is_err() {
            error!("Error: {}", text.err().unwrap());
            return false;
        }

        let path = {
            let ids : String = file.id().clone().into();
            format!("{}/{}-{}.imag", self.storepath, file.owning_module_name, ids)
        };

        self.ensure_store_path_exists();

        FSFile::create(&path).map(|mut fsfile| {
            fsfile.write_all(&text.unwrap().clone().into_bytes()[..])
        }).map_err(|writeerr|  {
            debug!("Could not create file at '{}'", path);
        }).and(Ok(true)).unwrap()
    }

    fn ensure_store_path_exists(&self) {
        use std::fs::create_dir_all;
        use std::process::exit;

        create_dir_all(&self.storepath).unwrap_or_else(|e| {
            error!("Could not create store: '{}'", self.storepath);
            error!("Error                 : '{}'", e);
            error!("Killing myself now");
            exit(1);
        })
    }

    pub fn load(&self, id: &FileID) -> Option<Rc<RefCell<File>>> {
        debug!("Loading '{:?}'", id);
        self.cache.borrow().get(id).cloned()
    }

    pub fn load_by_hash<HP>(&self,
                            m: &Module,
                            parser: &Parser<HP>,
                            hash: FileHash)
        -> Option<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        macro_rules! try_some {
            ($expr:expr) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return ::std::option::Option::None,
            });

            ($expr:expr => return) => (match $expr {
                ::std::option::Option::Some(val) => val,
                ::std::option::Option::None => return,
            })
        }

        use glob::{glob, Paths, PatternError};

        let hashstr : String = hash.into();
        let globstr = format!("{}/*-{}.imag", self.storepath, hashstr);
        debug!("glob({})", globstr);

        let globs = glob(&globstr[..]);
        if globs.is_err() {
            return None;
        }

        let path = globs.unwrap().last();
        debug!("path = {:?}", path);

        let pathbuf = try_some!(path);
        if pathbuf.is_err() { return None; }

        let pathbuf_un  = pathbuf.unwrap();
        let filename    = pathbuf_un.file_name();
        let s           = try_some!(filename).to_str();
        let string      = String::from(try_some!(s));
        let id          = try_some!(FileID::parse(&string));

        debug!("Loaded ID = '{:?}'", id);

        self.load_in_cache(m, parser, id)
            .map(|file| {
                debug!("Loaded File = '{:?}'", file);
                Some(file)
            }).unwrap_or(None)
    }

    pub fn remove(&self, id: FileID) -> bool {
        use std::fs::remove_file;

        self.cache
            .borrow_mut()
            .remove(&id)
            .map(|file| {
                let idstr : String = id.into();
                let path = format!("{}/{}-{}.imag",
                                   self.storepath,
                                   file.deref().borrow().owner_name(),
                                   idstr);
                debug!("Removing file NOW: '{}'", path);
                remove_file(path).is_ok()
            })
            .unwrap_or(false)
    }

    pub fn load_for_module<HP>(&self, m: &Module, parser: &Parser<HP>)
        -> Vec<Rc<RefCell<File>>>
        where HP: FileHeaderParser
    {
        use glob::{glob, Paths, PatternError};

        let globstr = format!("{}/{}-*.imag", self.storepath, m.name());
        let mut res = vec![];

        glob(&globstr[..]).map(|paths| {
            for path in paths {
                if let Ok(pathbuf) = path {
                    let fname = pathbuf.file_name().and_then(|s| s.to_str());
                    fname.map(|s| {
                        FileID::parse(&String::from(s)).map(|id| {
                            self.load_in_cache(m, parser, id).map(|file| {
                                res.push(file);
                            })
                        });
                    });
                }
            }
        });
        res
    }

    fn get_new_file_id(&self) -> FileID {
        use uuid::Uuid;
        let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
        FileID::new(FileIDType::UUID, hash)
    }

}
<|endoftext|>


<commit_before>use nix::sys::epoll::*;
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
use std::{thread, fmt, net, marker, slice};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::os::raw::c_int;
use std::os::unix::io::{RawFd, AsRawFd};
use std::io::Write;

use nix::sys::socket::*;
use nix::sys::signalfd::*;
use nix::sys::signal::{SIGINT, SIGTERM};
use nix::unistd;

use {Error, Result};
use io::controller::*;
use io::controller::sync::*;
use io::poll::*;

pub struct Server<F>
    where F: Factory + Send
{
    epfds: Vec<EpollFd>,
    srvfd: RawFd,
    factory: F,
    sockf: SockFlag,
    cepfd: EpollFd,
    signals: SignalFd,
    terminated: bool,
    io_cpus: usize,
    accepted: u64,
}

impl<F> Server<F>
    where F: Factory + Send + 'static
{
    pub fn new<A: ToSocketAddrs>(cepfd: EpollFd,
                             addr: A,
                             factory: F,
                             max_conn: usize,
                             sockf: SockFlag,
                             protocol: i32)
                             -> Result<Server<F>> {

        let srvfd: RawFd =
            try!(socket(AddressFamily::Inet, SockType::Stream, sockf, protocol)) as i32;

        let a = SockAddr::Inet(InetAddr::from_std(&addr.to_socket_addrs()
            .unwrap()
            .next()
            .unwrap()));

        try!(eagain!(bind, "bind", srvfd, &a));
        debug!("bind: success fd {} to {}", srvfd, a);

        try!(eagain!(listen, "listen", srvfd, max_conn));
        debug!("listen: success fd {}: {}", srvfd, a);

        // spawn one thread + epoll instance per
        // cpu, and leave one to take care of
        // connections
        let cpus = ::num_cpus::get();
        let io_cpus = cpus - 1;

        debug!("detected {} (v)cpus", cpus);

        let mut epfds: Vec<EpollFd> = Vec::with_capacity(io_cpus);

        for _ in 0..io_cpus {

            let epfd = EpollFd::new(try!(epoll_create()));

            epfds.push(epfd);

            thread::spawn(move || {
                let controller = SyncController::new(epfd, factory, max_conn);
                let mut epoll = Epoll::from_fd(epfd, controller, -1);
                perror!("loop()", epoll.run());
            });
        }

        debug!("created epoll instances: {:?}", epfds);

        let ceinfo = EpollEvent {
            events: EPOLLET | EPOLLIN | EPOLLOUT | EPOLLERR,
            data: srvfd as u64,
        };

        try!(cepfd.register(srvfd, &ceinfo));

        let mut mask = SigSet::empty();
        mask.add(SIGINT).unwrap();
        mask.add(SIGTERM).unwrap();
        mask.thread_block().unwrap();

        let signals = SignalFd::with_flags(&mask, SFD_NONBLOCK).unwrap();
        let sigfd = signals.as_raw_fd();

        let siginfo = EpollEvent {
            events: EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLRDHUP | EPOLLERR,
            data: sigfd as u64,
        };

        try!(cepfd.register(sigfd, &siginfo));

        Ok(Server {
            sockf: sockf,
            srvfd: srvfd,
            cepfd: cepfd,
            factory: factory,
            epfds: epfds,
            io_cpus: io_cpus,
            signals: signals,
            accepted: 0,
            terminated: false,
        })
    }
}

impl<F: Factory> Controller for Server<F> {
    fn is_terminated(&self) -> bool {
        self.terminated
    }

    fn ready(&mut self, ev: &EpollEvent) -> Result<()> {

        match ev.data {
            fd if fd == self.srvfd as u64 => {
                // TODO!!! Keep track of what fd is assigned to what epoll instance
                // and register interests for closed connections to do better
                // load balancing
                match eagain!(accept4, "accept4", self.srvfd, self.sockf) {
                    Ok(clifd) => {
                        debug!("accept4: acceted new tcp client {}", &clifd);

                        // round robin
                        let next = (self.accepted % self.io_cpus as u64) as usize;

                        let epfd: EpollFd = *self.epfds.get(next).unwrap();

                        let info = EpollEvent {
                            events: EPOLLONESHOT | EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLRDHUP,
                            // protocol is 0, as we are bound to one address only
                            data: self.factory.encode(Action::New(0, clifd)),
                        };

                        debug!("assigned client {} to epoll instance {}", &clifd, &epfd);

                        perror!("epoll_ctl", epfd.register(clifd, &info));

                        debug!("epoll_ctl: registered interests for {}", clifd);

                        self.accepted += 1;
                    }
                    Err(e) => error!("accept4: {}", e),
                }

            }
            _ => {
                match self.signals.read_signal() {
                    Ok(Some(sig)) => {
                        warn!("received signal: {:?}", sig.ssi_signo);
                        perror!("unistd::close", unistd::close(self.srvfd));
                    }
                    Ok(None) => (),
                    Err(err) => (), // some error happend
                }
            }
        }

        Ok(())
    }
}
<commit_msg>fixed signal handling<commit_after>use nix::sys::epoll::*;
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
use std::{thread, fmt, net, marker, slice};
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::os::raw::c_int;
use std::os::unix::io::{RawFd, AsRawFd};
use std::io::Write;

use nix::sys::socket::*;
use nix::sys::signalfd::*;
use nix::sys::signal::{SIGINT, SIGTERM};
use nix::unistd;

use {Error, Result};
use io::controller::*;
use io::controller::sync::*;
use io::poll::*;

pub struct Server<F>
    where F: Factory + Send
{
    epfds: Vec<EpollFd>,
    srvfd: RawFd,
    factory: F,
    sockf: SockFlag,
    cepfd: EpollFd,
    signals: SignalFd,
    terminated: bool,
    io_cpus: usize,
    accepted: u64,
}

impl<F> Server<F>
    where F: Factory + Send + 'static
{
    pub fn new<A: ToSocketAddrs>(cepfd: EpollFd,
                             addr: A,
                             factory: F,
                             max_conn: usize,
                             sockf: SockFlag,
                             protocol: i32)
                             -> Result<Server<F>> {

        let srvfd: RawFd =
            try!(socket(AddressFamily::Inet, SockType::Stream, sockf, protocol)) as i32;

        let a = SockAddr::Inet(InetAddr::from_std(&addr.to_socket_addrs()
            .unwrap()
            .next()
            .unwrap()));

        try!(eagain!(bind, "bind", srvfd, &a));
        debug!("bind: success fd {} to {}", srvfd, a);

        try!(eagain!(listen, "listen", srvfd, max_conn));
        debug!("listen: success fd {}: {}", srvfd, a);

        // spawn one thread + epoll instance per
        // cpu, and leave one to take care of
        // connections
        let cpus = ::num_cpus::get();
        let io_cpus = cpus - 1;

        debug!("detected {} (v)cpus", cpus);

        let mut epfds: Vec<EpollFd> = Vec::with_capacity(io_cpus);

        // build signal mask to share across threads
        let mut mask = SigSet::empty();
        mask.add(SIGINT).unwrap();
        mask.add(SIGTERM).unwrap();
        try!(mask.thread_set_mask());

        // add the set of signals to the signal mask
        // of the main thread
        mask.thread_block().unwrap();

        for _ in 0..io_cpus {

            let epfd = EpollFd::new(try!(epoll_create()));

            epfds.push(epfd);

            thread::spawn(move || {
                // add the set of signals to the signal mask for all threads
                // otherwise signalfd will not work properly
                mask.thread_block().unwrap();
                let controller = SyncController::new(epfd, factory, max_conn);
                let mut epoll = Epoll::from_fd(epfd, controller, -1);
                perror!("loop()", epoll.run());
            });
        }

        debug!("created epoll instances: {:?}", epfds);

        let ceinfo = EpollEvent {
            events: EPOLLET | EPOLLIN | EPOLLOUT | EPOLLERR,
            data: srvfd as u64,
        };

        try!(cepfd.register(srvfd, &ceinfo));

        let signals = SignalFd::with_flags(&mask, SFD_NONBLOCK).unwrap();
        let sigfd = signals.as_raw_fd();

        let siginfo = EpollEvent {
            events: EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLRDHUP | EPOLLERR,
            data: sigfd as u64,
        };

        try!(cepfd.register(sigfd, &siginfo));

        debug!("registered signalfd {}", sigfd);

        Ok(Server {
            sockf: sockf,
            srvfd: srvfd,
            cepfd: cepfd,
            factory: factory,
            epfds: epfds,
            io_cpus: io_cpus,
            signals: signals,
            accepted: 0,
            terminated: false,
        })
    }
}

impl<F: Factory> Controller for Server<F> {
    fn is_terminated(&self) -> bool {
        self.terminated
    }

    fn ready(&mut self, ev: &EpollEvent) -> Result<()> {

        match ev.data {
            fd if fd == self.srvfd as u64 => {
                // TODO!!! Keep track of what fd is assigned to what epoll instance
                // and register interests for closed connections to do better
                // load balancing
                match eagain!(accept4, "accept4", self.srvfd, self.sockf) {
                    Ok(clifd) => {
                        debug!("accept4: acceted new tcp client {}", &clifd);

                        // round robin
                        let next = (self.accepted % self.io_cpus as u64) as usize;

                        let epfd: EpollFd = *self.epfds.get(next).unwrap();

                        let info = EpollEvent {
                            events: EPOLLONESHOT | EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLRDHUP,
                            // protocol is 0, as we are bound to one address only
                            data: self.factory.encode(Action::New(0, clifd)),
                        };

                        debug!("assigned client {} to epoll instance {}", &clifd, &epfd);

                        perror!("epoll_ctl", epfd.register(clifd, &info));

                        debug!("epoll_ctl: registered interests for {}", clifd);

                        self.accepted += 1;
                    }
                    Err(e) => error!("accept4: {}", e),
                }

            }
            _ => {
                match self.signals.read_signal() {
                    // close server socket as the mask registered
                    // contains only SIGINT and SIGTERM
                    Ok(Some(sig)) => {
                        warn!("received signal {:?}. closing server socket..", sig.ssi_signo);
                        perror!("unistd::close", unistd::close(self.srvfd));
                        ::std::process::exit(1);
                    }
                    Ok(None) => {
                        warn!("signal fd woke up epoll but not ready to read");
                    },
                    Err(err) => {
                        error!("read_signal: {}", err);
                    }, // some error happend
                }
            }
        }

        Ok(())
    }
}
<|endoftext|>