<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/.

use std::io::Error;
use std::ops::DerefMut;
use std::sync::{Arc, Mutex};
use std::{mem, thread};
use std::net::{TcpStream, TcpListener};
use std::os::unix::io::{RawFd, AsRawFd, IntoRawFd};
use std::collections::LinkedList;

use libc;
use errno::errno;
use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use libc::{c_int, c_void};
use config::Config;
use openssl::ssl::{SslStream, SslContext};

use stats;
use types::*;
use resources::ResourcePool;
use ss::nonblocking::plain::Plain;
use ss::nonblocking::secure::Secure;
use ss::{Socket, Stream, SRecv, SSend, TcpOptions, SocketOptions};

// We need to be able to access our resource pool from several methods
static mut pool: *mut ResourcePool = 0 as *mut ResourcePool;

// Global SslContext
static mut ssl_context: *mut SslContext = 0 as *mut SslContext;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLET  - Fd is in EdgeTriggered mode (notification on state changes)
// EPOLLIN  - Data is available in kerndl buffer
const EVENTS: u32 = event_type::EPOLLET | event_type::EPOLLIN;

/// Starts the epoll wait and incoming connection listener threads.
pub fn begin(config: Config, handler: Box<EventHandler>) {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Stream>::new()));

    // Resource pool
    let mut rp = ResourcePool::new(config.workers);
    unsafe {
        pool = &mut rp;
    }

    // Wrap our event handler into something that can be safely shared
    // between threads.
    let e_handler = Handler(Box::into_raw(handler));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    let streams2 = sockets.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            event_loop(epfd2, streams2, e_handler);
        })
        .unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let streams3 = sockets.clone();
    let prox = thread::Builder::new()
                   .name("TCP Incoming Listener".to_string())
                   .spawn(move || {
                       listen(config, epfd3, streams3);
                   })
                   .unwrap();

    // Stay alive forever, or at least we hope
    let _ = prox.join();
}

/// Incoming connection listening thread
fn listen(config: Config, epfd: RawFd, streams: StreamList) {
    // Setup server and listening port
    let listener_result = try_setup_tcp_listener(&config);
    if listener_result.is_err() {
        error!("Setting up server: {}", listener_result.unwrap_err());
        return;
    }

    // If we're using SSL, setup our context reference
    if config.ssl.is_some() {
        setup_ssl_context(&config);
    }

    // Begin listening for new connections
    let listener = listener_result.unwrap();
    for accept_result in listener.incoming() {
        match accept_result {
            Ok(tcp_stream) => handle_new_connection(tcp_stream, &config, epfd, streams.clone()),
            Err(e) => error!("Accepting connection: {}", e)
        }
    }

    drop(listener);
}

fn try_setup_tcp_listener(config: &Config) -> Result<TcpListener, Error> {
    let create_result = TcpListener::bind((&config.addr[..], config.port));
    if create_result.is_err() {
        return create_result;
    }

    let listener = create_result.unwrap();
    let server_fd = listener.as_raw_fd();

    // Set the SO_REUSEADDR so that restarts after crashes do not take 5min to unbind
    // the initial port
    unsafe {
        let optval: c_int = 1;
        let opt_result = libc::setsockopt(server_fd,
                                          libc::SOL_SOCKET,
                                          libc::SO_REUSEADDR,
                                          &optval as *const _ as *const c_void,
                                          mem::size_of::<c_int>() as u32);
        if opt_result < 0 {
            return Err(Error::from_raw_os_error(errno().0 as i32));
        }
    }

    Ok(listener)
}

fn setup_ssl_context(config: &Config) {
    unsafe {
        ssl_context = Box::into_raw(Box::new(config.ssl.clone().unwrap()));
    }
}

fn handle_new_connection(tcp_stream: TcpStream, config: &Config, epfd: RawFd, streams: StreamList) {
    // Update our total opened file descriptors
    stats::fd_opened();

    // Create and configure a new socket
    let mut socket = Socket::new(tcp_stream.into_raw_fd());
    let result = setup_new_socket(&mut socket);
    if result.is_err() {
        close_fd(socket.as_raw_fd());
        return;
    }

    // Setup our stream
    let stream = match config.ssl {
        Some(_) => {
            let ssl_result = unsafe { SslStream::accept(&(*ssl_context), socket) };
            match ssl_result {
                Ok(ssl_stream) => {
                    let secure_stream = Secure::new(ssl_stream);
                    Stream::new(Box::new(secure_stream))
                }
                Err(ssl_error) => {
                    error!("Creating SslStream: {}", ssl_error);
                    return;
                }
            }
        }
        None => {
            let plain_text = Plain::new(socket);
            Stream::new(Box::new(plain_text))
        }
    };

    // Add stream to our server
    add_to_epoll(epfd, stream.as_raw_fd(), streams.clone());
    add_stream_to_master_list(stream, streams.clone());
}

fn setup_new_socket(socket: &mut Socket) -> Result<(), ()> {
    let result = socket.set_nonblocking();
    if result.is_err() {
        error!("Setting fd to nonblocking: {}", result.unwrap_err());
        return Err(());
    }

    let result = socket.set_tcp_nodelay(true);
    if result.is_err() {
        error!("Setting tcp_nodelay: {}", result.unwrap_err());
        return Err(());
    }

    let result = socket.set_tcp_keepalive(true);
    if result.is_err() {
        error!("Setting tcp_keepalive: {}", result.unwrap_err());
        return Err(());
    }

    Ok(())
}

/// Event loop for handling all epoll events
fn event_loop(epfd: RawFd, streams: StreamList, handler: Handler) {
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe {
        events.set_len(100);
    }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    handle_epoll_event(epfd, &events[x], streams.clone(), handler.clone());
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        };
    }
}

/// Finds the stream the epoll event is associated with and parses the event type
/// to hand off to specific handlers
fn handle_epoll_event(epfd: RawFd, event: &EpollEvent, streams: StreamList, handler: Handler) {
    const READ_EVENT: u32 = event_type::EPOLLIN;

    // Locate the stream the event was for
    let mut stream;
    {
        // Mutex lock
        // Find the stream the event was for
        let mut guard = match streams.lock() {
            Ok(guard) => guard,
            Err(poisoned) => {
                warn!("StreamList Mutex was poisoned, using anyway");
                poisoned.into_inner()
            }
        };
        let list = guard.deref_mut();

        let mut found = false;
        let mut index = 1usize;
        for s in list.iter() {
            if s.as_raw_fd() == event.data as RawFd {
                found = true;
                break;
            }
            index += 1;
        }

        if !found {
            error!("Could not find fd in stream list? Removing from epoll and closing fd");

            let fd = event.data as RawFd;
            remove_fd_from_epoll(epfd, fd);
            close_fd(fd);
            return;
        }

        if index == 1 {
            stream = list.pop_front().unwrap();
        } else {
            let mut split = list.split_off(index - 1);
            stream = split.pop_front().unwrap();
            list.append(&mut split);
        }
    } // Mutex unlock

    if (event.events & READ_EVENT) > 0 {
        trace!("event was read event");
        let _ = handle_read_event(epfd, &mut stream, handler).map(|_| {
            add_stream_to_master_list(stream, streams.clone());
        });
    } else {
        trace!("event was drop event");

        let fd = stream.as_raw_fd();
        remove_fd_from_epoll(epfd, fd);
        close_fd(fd);

        let stream_fd = stream.as_raw_fd();
        unsafe {
            (*pool).run(move || {
                let Handler(ptr) = handler;
                (*ptr).on_stream_closed(stream_fd);
            });
        }
    }
}

/// Reads all available data on the stream.
///
/// If a complete message(s) is available, each message will be routed through the
/// resource pool.
///
/// If an error occurs during the read, the stream is dropped from the server.
fn handle_read_event(epfd: RawFd, stream: &mut Stream, handler: Handler) -> Result<(), ()> {
    trace!("handle read event");

    match stream.recv() {
        Ok(_) => {
            let mut rx_queue = stream.drain_rx_queue();
            for payload in rx_queue.iter_mut() {
                // Check if this is a request for stats
                if payload.len() == 6 && payload[0] == 0x04 && payload[1] == 0x04 {
                    let u8ptr: *const u8 = &payload[2] as *const _;
                    let f32ptr: *const f32 = u8ptr as *const _;
                    let sec = unsafe { *f32ptr };
                    let stream_cpy = stream.clone();
                    unsafe {
                        (*pool).run(move || {
                            let mut s = stream_cpy.clone();
                            let result = stats::as_serialized_buffer(sec);
                            if result.is_ok() {
                                let _ = s.send(&result.unwrap()[..]);
                            }
                        });
                    }
                    return Ok(());
                }

                // TODO - Refactor once better function passing traits are available in stable.
                let handler_cpy = handler.clone();
                let stream_cpy = stream.clone();
                let payload_cpy = payload.clone();
                unsafe {
                    (*pool).run(move || {
                        let Handler(ptr) = handler_cpy;
                        (*ptr).on_data_received(stream_cpy.clone(), payload_cpy.clone());
                    });
                }
            }
            Ok(())
        }
        Err(e) => {
            error!("stream.fd: {} during read: {}", stream.as_raw_fd(), e);

            remove_fd_from_epoll(epfd, stream.as_raw_fd());
            close_fd(stream.as_raw_fd());

            let stream_fd = stream.as_raw_fd();
            unsafe {
                (*pool).run(move || {
                    let Handler(ptr) = handler;
                    (*ptr).on_stream_closed(stream_fd.clone());
                });
            }

            Err(())
        }
    }
}

/// Inserts the stream back into the master list of streams
fn add_stream_to_master_list(stream: Stream, streams: StreamList) {
    let mut guard = match streams.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("StreamList Mutex failed, using anyway...");
            poisoned.into_inner()
        }
    };
    let stream_list = guard.deref_mut();
    stream_list.push_back(stream);
    stats::conn_recv();
}

/// Adds a new fd to the epoll instance
fn add_to_epoll(epfd: RawFd, fd: RawFd, streams: StreamList) {
    let result = epoll::ctl(epfd,
                            ctl_op::ADD,
                            fd,
                            &mut EpollEvent {
                                data: fd as u64,
                                events: EVENTS,
                            });

    if result.is_ok() {
        trace!("New fd added to epoll");
    } else {
        let e = result.unwrap_err();
        error!("CtrlError during add: {}", e);
        remove_fd_from_list(fd, streams.clone());
        close_fd(fd);
    }
}

/// Removes a fd from the epoll instance
fn remove_fd_from_epoll(epfd: RawFd, fd: RawFd) {
    debug!("removing fd from epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL. We'll be as backwards compatible as possible.
    let _ = epoll::ctl(epfd,
                       ctl_op::DEL,
                       fd,
                       &mut EpollEvent {
                           data: 0 as u64,
                           events: 0 as u32,
                       })
                .map_err(|e| warn!("Epoll CtrlError during del: {}", e));
}

/// Removes stream with id from master list
fn remove_fd_from_list(fd: RawFd, streams: StreamList) {
    trace!("removing fd: {} from master list", fd);

    let mut guard = match streams.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("StreamList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let list = guard.deref_mut();

    let mut found = false;
    let mut index = 1usize;
    for s in list.iter() {
        if s.as_raw_fd() == fd {
            found = true;
            break;
        }
        index += 1;
    }

    if !found {
        trace!("fd: {} not found in list", fd);
        return;
    }

    if index == 1 {
        list.pop_front();
    } else {
        let mut split = list.split_off(index - 1);
        split.pop_front();
        list.append(&mut split);
    }

    stats::conn_lost();
}

/// Closes a fd with the kernel
fn close_fd(fd: RawFd) {
    unsafe {
        let result = libc::close(fd);
        if result < 0 {
            error!("Error closing fd: {}",
                   Error::from_raw_os_error(result as i32));
            return;
        }
    }
    stats::fd_closed();
}
<commit_msg>Adjust for streams now returning ErrorKind::WouldBlock<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/.

use std::io::{Error, ErrorKind};
use std::ops::DerefMut;
use std::sync::{Arc, Mutex};
use std::{mem, thread};
use std::net::{TcpStream, TcpListener};
use std::os::unix::io::{RawFd, AsRawFd, IntoRawFd};
use std::collections::LinkedList;

use libc;
use errno::errno;
use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use libc::{c_int, c_void};
use config::Config;
use openssl::ssl::{SslStream, SslContext};

use stats;
use types::*;
use resources::ResourcePool;
use ss::nonblocking::plain::Plain;
use ss::nonblocking::secure::Secure;
use ss::{Socket, Stream, SRecv, SSend, TcpOptions, SocketOptions};

// We need to be able to access our resource pool from several methods
static mut pool: *mut ResourcePool = 0 as *mut ResourcePool;

// Global SslContext
static mut ssl_context: *mut SslContext = 0 as *mut SslContext;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLET  - Fd is in EdgeTriggered mode (notification on state changes)
// EPOLLIN  - Data is available in kerndl buffer
const EVENTS: u32 = event_type::EPOLLET | event_type::EPOLLIN;

/// Starts the epoll wait and incoming connection listener threads.
pub fn begin(config: Config, handler: Box<EventHandler>) {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Stream>::new()));

    // Resource pool
    let mut rp = ResourcePool::new(config.workers);
    unsafe {
        pool = &mut rp;
    }

    // Wrap our event handler into something that can be safely shared
    // between threads.
    let e_handler = Handler(Box::into_raw(handler));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    let streams2 = sockets.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            event_loop(epfd2, streams2, e_handler);
        })
        .unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let streams3 = sockets.clone();
    let prox = thread::Builder::new()
                   .name("TCP Incoming Listener".to_string())
                   .spawn(move || {
                       listen(config, epfd3, streams3);
                   })
                   .unwrap();

    // Stay alive forever, or at least we hope
    let _ = prox.join();
}

/// Incoming connection listening thread
fn listen(config: Config, epfd: RawFd, streams: StreamList) {
    // Setup server and listening port
    let listener_result = try_setup_tcp_listener(&config);
    if listener_result.is_err() {
        error!("Setting up server: {}", listener_result.unwrap_err());
        return;
    }

    // If we're using SSL, setup our context reference
    if config.ssl.is_some() {
        setup_ssl_context(&config);
    }

    // Begin listening for new connections
    let listener = listener_result.unwrap();
    for accept_result in listener.incoming() {
        match accept_result {
            Ok(tcp_stream) => handle_new_connection(tcp_stream, &config, epfd, streams.clone()),
            Err(e) => error!("Accepting connection: {}", e)
        }
    }

    drop(listener);
}

fn try_setup_tcp_listener(config: &Config) -> Result<TcpListener, Error> {
    let create_result = TcpListener::bind((&config.addr[..], config.port));
    if create_result.is_err() {
        return create_result;
    }

    let listener = create_result.unwrap();
    let server_fd = listener.as_raw_fd();

    // Set the SO_REUSEADDR so that restarts after crashes do not take 5min to unbind
    // the initial port
    unsafe {
        let optval: c_int = 1;
        let opt_result = libc::setsockopt(server_fd,
                                          libc::SOL_SOCKET,
                                          libc::SO_REUSEADDR,
                                          &optval as *const _ as *const c_void,
                                          mem::size_of::<c_int>() as u32);
        if opt_result < 0 {
            return Err(Error::from_raw_os_error(errno().0 as i32));
        }
    }

    Ok(listener)
}

fn setup_ssl_context(config: &Config) {
    unsafe {
        ssl_context = Box::into_raw(Box::new(config.ssl.clone().unwrap()));
    }
}

fn handle_new_connection(tcp_stream: TcpStream, config: &Config, epfd: RawFd, streams: StreamList) {
    // Update our total opened file descriptors
    stats::fd_opened();

    // Create and configure a new socket
    let mut socket = Socket::new(tcp_stream.into_raw_fd());
    let result = setup_new_socket(&mut socket);
    if result.is_err() {
        close_fd(socket.as_raw_fd());
        return;
    }

    // Setup our stream
    let stream = match config.ssl {
        Some(_) => {
            let ssl_result = unsafe { SslStream::accept(&(*ssl_context), socket) };
            match ssl_result {
                Ok(ssl_stream) => {
                    let secure_stream = Secure::new(ssl_stream);
                    Stream::new(Box::new(secure_stream))
                }
                Err(ssl_error) => {
                    error!("Creating SslStream: {}", ssl_error);
                    return;
                }
            }
        }
        None => {
            let plain_text = Plain::new(socket);
            Stream::new(Box::new(plain_text))
        }
    };

    // Add stream to our server
    add_to_epoll(epfd, stream.as_raw_fd(), streams.clone());
    add_stream_to_master_list(stream, streams.clone());
}

fn setup_new_socket(socket: &mut Socket) -> Result<(), ()> {
    let result = socket.set_nonblocking();
    if result.is_err() {
        error!("Setting fd to nonblocking: {}", result.unwrap_err());
        return Err(());
    }

    let result = socket.set_tcp_nodelay(true);
    if result.is_err() {
        error!("Setting tcp_nodelay: {}", result.unwrap_err());
        return Err(());
    }

    let result = socket.set_tcp_keepalive(true);
    if result.is_err() {
        error!("Setting tcp_keepalive: {}", result.unwrap_err());
        return Err(());
    }

    Ok(())
}

/// Event loop for handling all epoll events
fn event_loop(epfd: RawFd, streams: StreamList, handler: Handler) {
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe {
        events.set_len(100);
    }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    handle_epoll_event(epfd, &events[x], streams.clone(), handler.clone());
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        };
    }
}

/// Finds the stream the epoll event is associated with and parses the event type
/// to hand off to specific handlers
fn handle_epoll_event(epfd: RawFd, event: &EpollEvent, streams: StreamList, handler: Handler) {
    const READ_EVENT: u32 = event_type::EPOLLIN;

    // Locate the stream the event was for
    let mut stream;
    {
        // Mutex lock
        // Find the stream the event was for
        let mut guard = match streams.lock() {
            Ok(guard) => guard,
            Err(poisoned) => {
                warn!("StreamList Mutex was poisoned, using anyway");
                poisoned.into_inner()
            }
        };
        let list = guard.deref_mut();

        let mut found = false;
        let mut index = 1usize;
        for s in list.iter() {
            if s.as_raw_fd() == event.data as RawFd {
                found = true;
                break;
            }
            index += 1;
        }

        if !found {
            error!("Could not find fd in stream list? Removing from epoll and closing fd");

            let fd = event.data as RawFd;
            remove_fd_from_epoll(epfd, fd);
            close_fd(fd);
            return;
        }

        if index == 1 {
            stream = list.pop_front().unwrap();
        } else {
            let mut split = list.split_off(index - 1);
            stream = split.pop_front().unwrap();
            list.append(&mut split);
        }
    } // Mutex unlock

    if (event.events & READ_EVENT) > 0 {
        trace!("event was read event");
        let _ = handle_read_event(epfd, &mut stream, handler).map(|_| {
            add_stream_to_master_list(stream, streams.clone());
        });
    } else {
        trace!("event was drop event");

        let fd = stream.as_raw_fd();
        remove_fd_from_epoll(epfd, fd);
        close_fd(fd);

        let stream_fd = stream.as_raw_fd();
        unsafe {
            (*pool).run(move || {
                let Handler(ptr) = handler;
                (*ptr).on_stream_closed(stream_fd);
            });
        }
    }
}

/// Reads all available data on the stream.
///
/// If a complete message(s) is available, each message will be routed through the
/// resource pool.
///
/// If an error occurs during the read, the stream is dropped from the server.
fn handle_read_event(epfd: RawFd, stream: &mut Stream, handler: Handler) -> Result<(), ()> {
    trace!("handle read event");

    match stream.recv() {
        Ok(_) => {
            let mut rx_queue = stream.drain_rx_queue();
            for payload in rx_queue.iter_mut() {
                // Check if this is a request for stats
                if payload.len() == 6 && payload[0] == 0x04 && payload[1] == 0x04 {
                    let u8ptr: *const u8 = &payload[2] as *const _;
                    let f32ptr: *const f32 = u8ptr as *const _;
                    let sec = unsafe { *f32ptr };
                    let stream_cpy = stream.clone();
                    unsafe {
                        (*pool).run(move || {
                            let mut s = stream_cpy.clone();
                            let result = stats::as_serialized_buffer(sec);
                            if result.is_ok() {
                                let _ = s.send(&result.unwrap()[..]);
                            }
                        });
                    }
                    return Ok(());
                }

                // TODO - Refactor once better function passing traits are available in stable.
                let handler_cpy = handler.clone();
                let stream_cpy = stream.clone();
                let payload_cpy = payload.clone();
                unsafe {
                    (*pool).run(move || {
                        let Handler(ptr) = handler_cpy;
                        (*ptr).on_data_received(stream_cpy.clone(), payload_cpy.clone());
                    });
                }
            }
            Ok(())
        }
        Err(e) => {
            if e.kind() == ErrorKind::WouldBlock {
                return Ok(());
            }

            error!("stream.fd: {} during read: {}", stream.as_raw_fd(), e);

            remove_fd_from_epoll(epfd, stream.as_raw_fd());
            close_fd(stream.as_raw_fd());

            let stream_fd = stream.as_raw_fd();
            unsafe {
                (*pool).run(move || {
                    let Handler(ptr) = handler;
                    (*ptr).on_stream_closed(stream_fd.clone());
                });
            }

            Err(())
        }
    }
}

/// Inserts the stream back into the master list of streams
fn add_stream_to_master_list(stream: Stream, streams: StreamList) {
    let mut guard = match streams.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("StreamList Mutex failed, using anyway...");
            poisoned.into_inner()
        }
    };
    let stream_list = guard.deref_mut();
    stream_list.push_back(stream);
    stats::conn_recv();
}

/// Adds a new fd to the epoll instance
fn add_to_epoll(epfd: RawFd, fd: RawFd, streams: StreamList) {
    let result = epoll::ctl(epfd,
                            ctl_op::ADD,
                            fd,
                            &mut EpollEvent {
                                data: fd as u64,
                                events: EVENTS,
                            });

    if result.is_ok() {
        trace!("New fd added to epoll");
    } else {
        let e = result.unwrap_err();
        error!("CtrlError during add: {}", e);
        remove_fd_from_list(fd, streams.clone());
        close_fd(fd);
    }
}

/// Removes a fd from the epoll instance
fn remove_fd_from_epoll(epfd: RawFd, fd: RawFd) {
    debug!("removing fd from epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL. We'll be as backwards compatible as possible.
    let _ = epoll::ctl(epfd,
                       ctl_op::DEL,
                       fd,
                       &mut EpollEvent {
                           data: 0 as u64,
                           events: 0 as u32,
                       })
                .map_err(|e| warn!("Epoll CtrlError during del: {}", e));
}

/// Removes stream with id from master list
fn remove_fd_from_list(fd: RawFd, streams: StreamList) {
    trace!("removing fd: {} from master list", fd);

    let mut guard = match streams.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("StreamList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let list = guard.deref_mut();

    let mut found = false;
    let mut index = 1usize;
    for s in list.iter() {
        if s.as_raw_fd() == fd {
            found = true;
            break;
        }
        index += 1;
    }

    if !found {
        trace!("fd: {} not found in list", fd);
        return;
    }

    if index == 1 {
        list.pop_front();
    } else {
        let mut split = list.split_off(index - 1);
        split.pop_front();
        list.append(&mut split);
    }

    stats::conn_lost();
}

/// Closes a fd with the kernel
fn close_fd(fd: RawFd) {
    unsafe {
        let result = libc::close(fd);
        if result < 0 {
            error!("Error closing fd: {}",
                   Error::from_raw_os_error(result as i32));
            return;
        }
    }
    stats::fd_closed();
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate string_telephone;
extern crate collections;

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket};

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        loop {
            loop {
                match server.poll() {
                    Some((UserPacket(packet), _)) => {
                        server.send_to_all(&packet);
                    },
                    Some(_) => (),
                    None => break
                }
            };
            let culled = server.cull();
            if culled.len() > 0 {
                println!("{}", culled);
            }
        }
    }
}
<commit_msg>Started putting together server loop<commit_after>extern crate piston;
extern crate string_telephone;
extern crate collections;

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, NoWindow};
use string_telephone::{Server, ConnectionConfig, UserPacket};

struct Player {
    controller: SocketAddr,
    x: uint,
    y: uint
}

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let mut window = NoWindow::new(WindowSettings {
        title: "SuperMegaTag".to_string(),
        size: [0u32, 0u32],
        samples: 0,
        fullscreen: false,
        exit_on_esc: true,
    });

    let game_iter_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };

    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    let mut server = match Server::new(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 8869}, settings) {
        Ok(server) => {
            println!("Listening on {}", server.addr);
            server
        },
        Err(e) => fail!("Failed to start listening - {}", e)
    };

    for e in EventIterator::new(&mut window, &game_iter_settings) {
        loop {
            match server.poll() {
                Some((UserPacket(packet), _)) => {
                    //Do something
                },
                Some(_) => (),
                None => break
            }
        };

        let culled = server.cull();
        if culled.len() > 0 {
            println!("{}", culled);
        }
    }
}
<|endoftext|>


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

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

use std::io::prelude::*;
//use std::io::BufReader;

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

use self::uuid::Uuid;

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

pub struct Server {
    clients: Vec<ClientBase>, // this always grows
    players: HashMap<Uuid, Player>,
    pub dist_tx: Sender<DistKind<TcpStream>>,
    store: Store,
}

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

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

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

        server.clients = server.store.clients_get();
        let server = Arc::new(Mutex::new(server)); //FIXME: mutex glom needs to go

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

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

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

        let mut client_id: Option<Uuid> = None;

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    0 => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_nicks(&mut server, uuid);
                        }
                    },
                    1 => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                2 => { //chat
                                    Server::chat(&mut server, &mut s, uuid);
                                },
                                3 => { //nick
                                    Server::nick(&mut server, &mut s, uuid);
                                },
                                _ => panic!("unknown cmd:{:?}",cmd)
                            }
                        }
                    }
                }
            }
            else { break } //drop dead client
        }

        println!("client dropped");
    }

    fn register (server: &mut Arc<Mutex<Server>>,
                 mut s: &mut TcpStream,) {
        if let Some(c) = Client::load(&mut s) {
            let mut server = server.lock().unwrap();

            for n in server.clients.iter() {
                if &n.id == c.id() { continue }
            }

            let mut r = false;
            for _ in [..100].iter() { // try to repeatedly add a unique name
                let mut nick = "player_".to_string();
                nick.push_str(&rand::random::<u16>().to_string());
                r = server.store.player_put(&c.id(), &Player { nick: nick });
                if r { break }
            }

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

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

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

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

            let server = server.lock().unwrap();
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

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

    #[allow(unused_must_use)]
    fn nick (server: &mut Arc<Mutex<Server>>,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            let r = {
                let server = server.lock().unwrap();
                server.store.player_update(&uuid, &Player { nick: text.clone() })
            };

            if r {
                Server::send_nick(server, uuid,&text);
                println!("nick_change:{:?}  {:?}",uuid,text);
            }
        }
    }
     #[allow(unused_must_use)]
    fn send_nick (server: &mut Arc<Mutex<Server>>,
                  uuid: Uuid,
                  nick: &String) {
        //broadcast
        let (mut data, bytes) = text_as_bytes(nick);
        data[0] = 3; //change opcode to nick
        data.extend_from_slice(bytes);
        data.extend_from_slice(uuid.as_bytes()); //refer to uuid

        let server = server.lock().unwrap();
        server.dist_tx.send(DistKind::Broadcast(data));
    }

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

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

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

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {
                    {
                        let mut server = server.lock().unwrap();
                        player = server.store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                let mut server = server.lock().unwrap();
                                server.dist_tx.send(DistKind::Add(*c.id(),stmp));
                                server.players.insert(*c.id(),player.clone());
                                println!("total players:{:?}",server.players.len());
                            }

                            println!("login:{:?}",c.id());
                            Server::send_nick(server, *c.id(), &player.nick);
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

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

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_nicks (server: &mut Arc<Mutex<Server>>,
                   uuid: Uuid)  {
        let server = server.lock().unwrap();

        for (ref pid,player) in server.players.iter() {
            let (mut data, bytes) = text_as_bytes(&player.nick);
            data[0] = 3; // specify nick route

            data.extend_from_slice(bytes);
            data.extend_from_slice(pid.as_bytes()); //refer to uuid

            server.dist_tx.send(DistKind::Select(uuid,data));
        }
    }
}
<commit_msg>rename<commit_after>use std::net::{TcpListener, TcpStream};
use std::collections::HashMap;

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

use std::io::prelude::*;
//use std::io::BufReader;

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

use self::uuid::Uuid;

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

pub struct Server {
    clients: Vec<ClientBase>, // this always grows
    players: HashMap<Uuid, Player>,
    dist: Sender<DistKind<TcpStream>>,
    store: Store,
}

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

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

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

        server.clients = server.store.clients_get();
        let server = Arc::new(Mutex::new(server)); //FIXME: mutex glom needs to go

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

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

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

        let mut client_id: Option<Uuid> = None;

        loop {
            if let Ok(_) = s.read_exact(&mut cmd) {
                match cmd[0] {
                    0 => { //login
                        client_id = Server::login(&mut server, &mut s, m);
                        if let Some(uuid) = client_id {
                            Server::send_nicks(&mut server, uuid);
                        }
                    },
                    1 => { //register
                        Server::register(&mut server, &mut s);
                    },
                    _ => {
                        if let Some(uuid) = client_id {
                            match cmd[0] {
                                2 => { //chat
                                    Server::chat(&mut server, &mut s, uuid);
                                },
                                3 => { //nick
                                    Server::nick(&mut server, &mut s, uuid);
                                },
                                _ => panic!("unknown cmd:{:?}",cmd)
                            }
                        }
                    }
                }
            }
            else { break } //drop dead client
        }

        println!("client dropped");
    }

    fn register (server: &mut Arc<Mutex<Server>>,
                 mut s: &mut TcpStream,) {
        if let Some(c) = Client::load(&mut s) {
            let mut server = server.lock().unwrap();

            for n in server.clients.iter() {
                if &n.id == c.id() { continue }
            }

            let mut r = false;
            for _ in [..100].iter() { // try to repeatedly add a unique name
                let mut nick = "player_".to_string();
                nick.push_str(&rand::random::<u16>().to_string());
                r = server.store.player_put(&c.id(), &Player { nick: nick });
                if r { break }
            }

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

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

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

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

            let server = server.lock().unwrap();
            data.extend_from_slice(uuid.as_bytes()); //refer to uuid

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

    #[allow(unused_must_use)]
    fn nick (server: &mut Arc<Mutex<Server>>,
             mut s: &mut TcpStream,
             uuid: Uuid) {

        if let Some(text) = read_text(s) {
            let r = {
                let server = server.lock().unwrap();
                server.store.player_update(&uuid, &Player { nick: text.clone() })
            };

            if r {
                Server::send_nick(server, uuid,&text);
                println!("nick_change:{:?}  {:?}",uuid,text);
            }
        }
    }
     #[allow(unused_must_use)]
    fn send_nick (server: &mut Arc<Mutex<Server>>,
                  uuid: Uuid,
                  nick: &String) {
        //broadcast
        let (mut data, bytes) = text_as_bytes(nick);
        data[0] = 3; //change opcode to nick
        data.extend_from_slice(bytes);
        data.extend_from_slice(uuid.as_bytes()); //refer to uuid

        let server = server.lock().unwrap();
        server.dist.send(DistKind::Broadcast(data));
    }

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

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

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

                        break
                    }
                }
            }

            if let Some(key) = reg_key {
                let hm = hmacsha1::hmac_sha1(&key, m.as_bytes());
                if c.key() == hm {
                    {
                        let mut server = server.lock().unwrap();
                        player = server.store.player_get(c.id());
                    }

                    if let Some(player) = player {
                        if let Ok(stmp) = s.try_clone() {
                            {
                                let mut server = server.lock().unwrap();
                                server.dist.send(DistKind::Add(*c.id(),stmp));
                                server.players.insert(*c.id(),player.clone());
                                println!("total players:{:?}",server.players.len());
                            }

                            println!("login:{:?}",c.id());
                            Server::send_nick(server, *c.id(), &player.nick);
                        }
                    }
                }
                else {
                    panic!("client invalid login {:?}", c)
                }

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

       client_id
    }

    #[allow(unused_must_use)]
    //NOTE: this is very innefficient, and hogs the mutex
    //TODO: rework state updates entirely
    fn send_nicks (server: &mut Arc<Mutex<Server>>,
                   uuid: Uuid)  {
        let server = server.lock().unwrap();

        for (ref pid,player) in server.players.iter() {
            let (mut data, bytes) = text_as_bytes(&player.nick);
            data[0] = 3; // specify nick route

            data.extend_from_slice(bytes);
            data.extend_from_slice(pid.as_bytes()); //refer to uuid

            server.dist.send(DistKind::Select(uuid,data));
        }
    }
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, TcpStream};
use std::old_io::{Acceptor, Listener};
use std::thread;
use std::io::{Read, Write};

extern crate std;

use query_executor::handle_query;

#[cfg(not(test))]
pub fn start() {
    let listener = TcpListener::bind("127.0.0.1:8888").unwrap();
    for stream in listener.incoming() {
        match stream {
            Err(err) => {
                println!("{}", err);
                break
            }
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream)
                });
            }
        }
    }

    drop(listener);
}

fn handle_client<T: Read + Write>(mut stream: T) {
    let mut buf = [0; 4096];
    loop {
        match stream.read(&mut buf) {
            Err(err) => {
                println!("{}", err);
                break
            },
            Ok(0) => {
                println!("connection closed");
                break
            },
            Ok(amount_read) => {
                println!("read {} bytes", amount_read);
                let read = buf.slice(0, amount_read);
                let read_string = std::str::from_utf8(read).ok().unwrap().trim();
                println!("read: \"{}\"", read_string);
                let response = handle_query(read_string);
                println!("responding: \"{}\"", response);
                stream.write(format!("{}\n", response).as_bytes());
            }
        }
    };
}
<commit_msg>improve logging<commit_after>use std::net::{TcpListener, TcpStream};
use std::old_io::{Acceptor, Listener};
use std::thread;
use std::io::{Read, Write};

extern crate std;

use query_executor::handle_query;

#[cfg(not(test))]
pub fn start() {
    let listener = TcpListener::bind("127.0.0.1:8888").unwrap();
    for stream in listener.incoming() {
        match stream {
            Err(err) => {
                println!("{}", err);
                break
            }
            Ok(stream) => {
                thread::spawn(move|| {
                    handle_client(stream)
                });
            }
        }
    }

    drop(listener);
}

fn handle_client(mut stream: TcpStream) {
    let mut buf = [0; 4096];
    loop {
        match stream.read(&mut buf) {
            Err(err) => {
                println!("{}", err);
                break
            },
            Ok(0) => {
                println!("connection closed");
                break
            },
            Ok(amount_read) => {
                let read = buf.slice(0, amount_read);
                let read_string = std::str::from_utf8(read).ok().unwrap().trim();
                log(&stream, format!("read: \"{}\"", read_string));
                let response = handle_query(read_string);
                log(&stream, format!("resp: \"{}\"", response));
                stream.write(format!("{}\n", response).as_bytes());
            }
        }
    };
}

fn log(stream: &TcpStream, message: String) {
    println!("remote={}: {}", stream.peer_addr().ok().unwrap(), message);
}
<|endoftext|>


<commit_before>// Copyright 2016 ZFilexfer Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use arbitrator::Arbitrator;
use czmq::{ZFrame, ZMsg, ZSock, ZSys};
use error::{Error, Result};
use file::File;
use std::collections::HashMap;
use std::result::Result as StdResult;
use zdaemon::{Endpoint, Error as DError, ZMsgExtended};

pub struct Server {
    router: ZSock,
    sink: ZSock,
    files: HashMap<Vec<u8>, File>,
    arbitrator: Arbitrator,
    arbitrator_sock: ZSock,
}

impl Server {
    pub fn new(router: ZSock, upload_slots: u32) -> Result<Server> {
        // Would use RC instead of pipe, however RC !Send and Arc
        // +Sync & ZSock !Sync.
        let (s_sock, a_sock) = try!(ZSys::create_pipe());
        let arbitrator = try!(Arbitrator::new(a_sock, upload_slots));

        Ok(Server {
            router: router,
            sink: try!(ZSock::new_pull("inproc://zfilexfer_sink")),
            files: HashMap::new(),
            arbitrator: arbitrator,
            arbitrator_sock: s_sock,
        })
    }

    fn reply_err(&mut self, router_id: &[u8], err: Error) -> StdResult<(), DError> {
        let msg = try!(ZMsg::new_err(&err.into(), None));
        try!(msg.pushbytes(router_id));
        try!(msg.send(&mut self.router));
        Ok(())
    }
}

impl Endpoint for Server {
    fn get_sockets(&mut self) -> Vec<&mut ZSock> {
        vec![&mut self.router, &mut self.sink, &mut self.arbitrator_sock]
    }

    fn recv(&mut self, sock: &mut ZSock) -> StdResult<(), DError> {
        // We always expect a router ID as it ties a request to a
        // file. Its presence is not dependent on the socket type.
        let router_id = match try!(try!(ZFrame::recv(sock)).data()) {
            Ok(s) => s.into_bytes(),
            Err(b) => b,
        };

        if *sock == self.router {
            if let Ok(action) = try!(try!(ZFrame::recv(sock)).data()) {
                match action.as_ref() {
                    "NEW" => {
                        let msg = try!(ZMsg::expect_recv(sock, 5, Some(5), false));

                        let path = match msg.popstr().unwrap() {
                            Ok(p) => p,
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let size = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let crc = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let chunk_size = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let options = match msg.popstr().unwrap() {
                            Ok(s) => s,
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let file = match File::create(&mut self.arbitrator, &router_id, &path, size, crc, chunk_size, &options) {
                            Ok(f) => f,
                            Err(e) => return self.reply_err(&router_id, e),
                        };

                        self.files.insert(router_id, file);
                    },
                    "CHUNK" => {
                        if !self.files.contains_key(&router_id) {
                            return self.reply_err(&router_id, Error::InvalidRequest);
                        }

                        let msg = try!(ZMsg::expect_recv(sock, 2, Some(2), false));

                        let index = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let chunk = try!(msg.popbytes()).unwrap();

                        if let Err(e) = self.files.get_mut(&router_id).unwrap().recv(&router_id, index, chunk) {
                            return self.reply_err(&router_id, e);
                        }
                    },
                    _ => return Err(Error::InvalidRequest.into()),
                }
            }
        }
        else if *sock == self.sink {
            if !self.files.contains_key(&router_id) {
                return Err(Error::InvalidRequest.into());
            }

            let msg = try!(ZMsg::expect_recv(sock, 2, Some(2), false));

            // We can make the assumption here that the data is well
            // formed, as there are no user-provided fields.
            let index = msg.popstr().unwrap().unwrap().parse::<u64>().unwrap();
            let success = if msg.popstr().unwrap().unwrap() == "1" { true } else { false };

            let mut file = self.files.get_mut(&router_id).unwrap();

            if let Err(e) = file.sink(&mut self.arbitrator, &router_id, index, success) {
                return Err(e.into());
            }

            if file.is_error() {
                try!(ZMsg::new_err(&Error::FileFail.into(), None));
                try!(msg.pushbytes(&router_id));
                try!(msg.send(&mut self.router));
            }
            else if file.is_complete() {
                let msg = match file.save() {
                    Ok(_) => try!(ZMsg::new_ok(None)),
                    Err(e) => try!(ZMsg::new_err(&e.into(), None)),
                };
                try!(msg.pushbytes(&router_id));
                try!(msg.send(&mut self.router));
            }
        }
        else if *sock == self.arbitrator_sock {
            // Forward messages from Arbitrator to Router sock
            let msg = try!(ZMsg::recv(sock));
            try!(msg.pushbytes(&router_id));
            try!(msg.send(&mut self.router));
        } else {
            unreachable!();
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use arbitrator::Arbitrator;
    use czmq::{RawInterface, ZFrame, ZMsg, ZSock, SocketType, ZSys};
    use error::Error;
    use file::File;
    use std::collections::HashMap;
    use super::*;
    use tempdir::TempDir;
    use zdaemon::Endpoint;

    #[test]
    fn test_new() {
        ZSys::init();

        let router = ZSock::new(SocketType::ROUTER);
        assert!(Server::new(router, 0).is_ok());
    }

    #[test]
    fn test_reply_err() {
        ZSys::init();

        let mut dealer = ZSock::new_dealer("inproc://server_test_reply_err").unwrap();
        dealer.set_sndtimeo(Some(500));
        dealer.set_rcvtimeo(Some(500));
        let mut router = ZSock::new_router("inproc://server_test_reply_err").unwrap();
        router.set_sndtimeo(Some(500));
        router.set_rcvtimeo(Some(500));

        dealer.send_str("moo").unwrap();
        let router_id = match ZFrame::recv(&mut router).unwrap().data().unwrap() {
            Ok(s) => s.into_bytes(),
            Err(b) => b,
        };
        router.flush();

        let mut server = new_server(router, true);
        assert!(server.reply_err(&router_id, Error::InvalidRequest).is_ok());

        let reply = ZFrame::recv(&mut dealer).unwrap().data().unwrap().unwrap();
        assert_eq!(&reply, "Err");
    }

    #[test]
    fn test_recv_new() {
        ZSys::init();

        let mut dealer = ZSock::new_dealer("inproc://server_test_recv_new").unwrap();
        dealer.set_sndtimeo(Some(500));
        dealer.set_rcvtimeo(Some(500));
        let mut router = ZSock::new_router("inproc://server_test_recv_new").unwrap();
        router.set_sndtimeo(Some(500));
        router.set_rcvtimeo(Some(500));
        let mut router_dup = unsafe { ZSock::from_raw(router.as_mut_ptr(), false) };

        let mut server = new_server(router, true);

        let msg = ZMsg::new();
        msg.addstr("NEW").unwrap();
        msg.addstr("/path/to/file").unwrap();
        msg.addstr("abc").unwrap();
        msg.addstr("0").unwrap();
        msg.addstr("1").unwrap();
        msg.addstr("{}").unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();
        assert_eq!(server.files.len(), 0);

        let msg = ZMsg::recv(&mut dealer).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Err");
        assert_eq!(msg.popstr().unwrap().unwrap(), "Invalid request");

        let tempdir = TempDir::new("server_test_recv_new").unwrap();

        let msg = ZMsg::new();
        msg.addstr("NEW").unwrap();
        msg.addstr(&format!("{}/testfile", tempdir.path().to_str().unwrap())).unwrap();
        msg.addstr("10240").unwrap();
        msg.addstr("0").unwrap();
        msg.addstr("1024").unwrap();
        msg.addstr("{}").unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();
        assert_eq!(server.files.len(), 1);

        assert!(dealer.recv_str().is_err());
    }

    #[test]
    fn test_recv_chunk() {
        ZSys::init();

        let mut dealer = ZSock::new_dealer("inproc://server_test_recv_chunk").unwrap();
        dealer.set_sndtimeo(Some(500));
        dealer.set_rcvtimeo(Some(500));
        let mut router = ZSock::new_router("inproc://server_test_recv_chunk").unwrap();
        router.set_sndtimeo(Some(500));
        router.set_rcvtimeo(Some(500));
        let mut router_dup = unsafe { ZSock::from_raw(router.as_mut_ptr(), false) };

        dealer.send_str("test").unwrap();
        let router_id = match ZFrame::recv(&mut router).unwrap().data().unwrap() {
            Ok(s) => s.into_bytes(),
            Err(b) => b,
        };
        router.flush();

        let mut server = new_server(router, true);

        let msg = ZMsg::new();
        msg.addstr("CHUNK").unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();

        let msg = ZMsg::recv(&mut dealer).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Err");
        assert_eq!(msg.popstr().unwrap().unwrap(), "Invalid request");

        let tempdir = TempDir::new("server_test_recv_chunk").unwrap();
        let file = File::create(&mut server.arbitrator, "abc".as_bytes(), &format!("{}/testfile", tempdir.path().to_str().unwrap()), 0, 0, 1, "{}").unwrap();
        server.files.insert(router_id, file);

        let msg = ZMsg::new();
        msg.addstr("CHUNK").unwrap();
        msg.addstr("1").unwrap();
        msg.addbytes("bytes".as_bytes()).unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();

        let msg = ZMsg::recv(&mut dealer).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Err");
        assert_eq!(msg.popstr().unwrap().unwrap(), "Chunk index not in file");
    }

    #[test]
    fn test_recv_sink() {
        ZSys::init();

        let mut worker = ZSock::new_push("inproc://server_test_recv_sink").unwrap();
        let mut sink = ZSock::new_pull("inproc://server_test_recv_sink").unwrap();
        let mut sink_dup = unsafe { ZSock::from_raw(sink.as_mut_ptr(), false) };

        let mut server = new_server(sink, false);
        let tempdir = TempDir::new("server_test_recv_chunk").unwrap();
        let file = File::create(&mut server.arbitrator, "abc".as_bytes(), &format!("{}/testfile", tempdir.path().to_str().unwrap()), 1, 0, 1, "{}").unwrap();
        server.files.insert("abc".as_bytes().into(), file);

        let msg = ZMsg::new();
        msg.addstr("abc").unwrap();
        msg.addstr("0").unwrap();
        msg.addstr("1").unwrap();
        msg.send(&mut worker).unwrap();

        assert!(server.recv(&mut sink_dup).is_ok());
    }

    fn new_server(sock: ZSock, is_router: bool) -> Server {
        let router;
        let sink;
        if is_router {
            router = sock;
            sink = ZSock::new(SocketType::PULL);
        } else {
            router = ZSock::new(SocketType::ROUTER);
            sink = sock;
        }

        let (s_sock, a_sock) = ZSys::create_pipe().unwrap();
        let arbitrator = Arbitrator::new(a_sock, 0).unwrap();

        Server {
            router: router,
            sink: sink,
            files: HashMap::new(),
            arbitrator: arbitrator,
            arbitrator_sock: s_sock,
        }
    }
}
<commit_msg>Compat with ZDaemon update<commit_after>// Copyright 2016 ZFilexfer Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use arbitrator::Arbitrator;
use czmq::{ZFrame, ZMsg, ZSock, ZSys};
use error::{Error, Result};
use file::File;
use std::collections::HashMap;
use std::result::Result as StdResult;
use zdaemon::{Endpoint, Error as DError, ZMsgExtended};

pub struct Server {
    router: ZSock,
    sink: ZSock,
    files: HashMap<Vec<u8>, File>,
    arbitrator: Arbitrator,
    arbitrator_sock: ZSock,
}

impl Server {
    pub fn new(router: ZSock, upload_slots: u32) -> Result<Server> {
        // Would use RC instead of pipe, however RC !Send and Arc
        // +Sync & ZSock !Sync.
        let (s_sock, a_sock) = try!(ZSys::create_pipe());
        let arbitrator = try!(Arbitrator::new(a_sock, upload_slots));

        Ok(Server {
            router: router,
            sink: try!(ZSock::new_pull("inproc://zfilexfer_sink")),
            files: HashMap::new(),
            arbitrator: arbitrator,
            arbitrator_sock: s_sock,
        })
    }

    fn reply_err(&mut self, router_id: &[u8], err: Error) -> StdResult<(), DError> {
        let msg = try!(ZMsg::new_err(&err.into()));
        try!(msg.pushbytes(router_id));
        try!(msg.send(&mut self.router));
        Ok(())
    }
}

impl Endpoint for Server {
    fn get_sockets(&mut self) -> Vec<&mut ZSock> {
        vec![&mut self.router, &mut self.sink, &mut self.arbitrator_sock]
    }

    fn recv(&mut self, sock: &mut ZSock) -> StdResult<(), DError> {
        // We always expect a router ID as it ties a request to a
        // file. Its presence is not dependent on the socket type.
        let router_id = match try!(try!(ZFrame::recv(sock)).data()) {
            Ok(s) => s.into_bytes(),
            Err(b) => b,
        };

        if *sock == self.router {
            if let Ok(action) = try!(try!(ZFrame::recv(sock)).data()) {
                match action.as_ref() {
                    "NEW" => {
                        let msg = try!(ZMsg::expect_recv(sock, 5, Some(5), false));

                        let path = match msg.popstr().unwrap() {
                            Ok(p) => p,
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let size = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let crc = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let chunk_size = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let options = match msg.popstr().unwrap() {
                            Ok(s) => s,
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let file = match File::create(&mut self.arbitrator, &router_id, &path, size, crc, chunk_size, &options) {
                            Ok(f) => f,
                            Err(e) => return self.reply_err(&router_id, e),
                        };

                        self.files.insert(router_id, file);
                    },
                    "CHUNK" => {
                        if !self.files.contains_key(&router_id) {
                            return self.reply_err(&router_id, Error::InvalidRequest);
                        }

                        let msg = try!(ZMsg::expect_recv(sock, 2, Some(2), false));

                        let index = match msg.popstr().unwrap() {
                            Ok(s) => match s.parse::<u64>() {
                                Ok(u) => u,
                                Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                            },
                            Err(_) => return self.reply_err(&router_id, Error::InvalidRequest),
                        };

                        let chunk = try!(msg.popbytes()).unwrap();

                        if let Err(e) = self.files.get_mut(&router_id).unwrap().recv(&router_id, index, chunk) {
                            return self.reply_err(&router_id, e);
                        }
                    },
                    _ => return Err(Error::InvalidRequest.into()),
                }
            }
        }
        else if *sock == self.sink {
            if !self.files.contains_key(&router_id) {
                return Err(Error::InvalidRequest.into());
            }

            let msg = try!(ZMsg::expect_recv(sock, 2, Some(2), false));

            // We can make the assumption here that the data is well
            // formed, as there are no user-provided fields.
            let index = msg.popstr().unwrap().unwrap().parse::<u64>().unwrap();
            let success = if msg.popstr().unwrap().unwrap() == "1" { true } else { false };

            let mut file = self.files.get_mut(&router_id).unwrap();

            if let Err(e) = file.sink(&mut self.arbitrator, &router_id, index, success) {
                return Err(e.into());
            }

            if file.is_error() {
                try!(ZMsg::new_err(&Error::FileFail.into()));
                try!(msg.pushbytes(&router_id));
                try!(msg.send(&mut self.router));
            }
            else if file.is_complete() {
                let msg = match file.save() {
                    Ok(_) => try!(ZMsg::new_ok()),
                    Err(e) => try!(ZMsg::new_err(&e.into())),
                };
                try!(msg.pushbytes(&router_id));
                try!(msg.send(&mut self.router));
            }
        }
        else if *sock == self.arbitrator_sock {
            // Forward messages from Arbitrator to Router sock
            let msg = try!(ZMsg::recv(sock));
            try!(msg.pushbytes(&router_id));
            try!(msg.send(&mut self.router));
        } else {
            unreachable!();
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use arbitrator::Arbitrator;
    use czmq::{RawInterface, ZFrame, ZMsg, ZSock, SocketType, ZSys};
    use error::Error;
    use file::File;
    use std::collections::HashMap;
    use super::*;
    use tempdir::TempDir;
    use zdaemon::Endpoint;

    #[test]
    fn test_new() {
        ZSys::init();

        let router = ZSock::new(SocketType::ROUTER);
        assert!(Server::new(router, 0).is_ok());
    }

    #[test]
    fn test_reply_err() {
        ZSys::init();

        let mut dealer = ZSock::new_dealer("inproc://server_test_reply_err").unwrap();
        dealer.set_sndtimeo(Some(500));
        dealer.set_rcvtimeo(Some(500));
        let mut router = ZSock::new_router("inproc://server_test_reply_err").unwrap();
        router.set_sndtimeo(Some(500));
        router.set_rcvtimeo(Some(500));

        dealer.send_str("moo").unwrap();
        let router_id = match ZFrame::recv(&mut router).unwrap().data().unwrap() {
            Ok(s) => s.into_bytes(),
            Err(b) => b,
        };
        router.flush();

        let mut server = new_server(router, true);
        assert!(server.reply_err(&router_id, Error::InvalidRequest).is_ok());

        let reply = ZFrame::recv(&mut dealer).unwrap().data().unwrap().unwrap();
        assert_eq!(&reply, "Err");
    }

    #[test]
    fn test_recv_new() {
        ZSys::init();

        let mut dealer = ZSock::new_dealer("inproc://server_test_recv_new").unwrap();
        dealer.set_sndtimeo(Some(500));
        dealer.set_rcvtimeo(Some(500));
        let mut router = ZSock::new_router("inproc://server_test_recv_new").unwrap();
        router.set_sndtimeo(Some(500));
        router.set_rcvtimeo(Some(500));
        let mut router_dup = unsafe { ZSock::from_raw(router.as_mut_ptr(), false) };

        let mut server = new_server(router, true);

        let msg = ZMsg::new();
        msg.addstr("NEW").unwrap();
        msg.addstr("/path/to/file").unwrap();
        msg.addstr("abc").unwrap();
        msg.addstr("0").unwrap();
        msg.addstr("1").unwrap();
        msg.addstr("{}").unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();
        assert_eq!(server.files.len(), 0);

        let msg = ZMsg::recv(&mut dealer).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Err");
        assert_eq!(msg.popstr().unwrap().unwrap(), "Invalid request");

        let tempdir = TempDir::new("server_test_recv_new").unwrap();

        let msg = ZMsg::new();
        msg.addstr("NEW").unwrap();
        msg.addstr(&format!("{}/testfile", tempdir.path().to_str().unwrap())).unwrap();
        msg.addstr("10240").unwrap();
        msg.addstr("0").unwrap();
        msg.addstr("1024").unwrap();
        msg.addstr("{}").unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();
        assert_eq!(server.files.len(), 1);

        assert!(dealer.recv_str().is_err());
    }

    #[test]
    fn test_recv_chunk() {
        ZSys::init();

        let mut dealer = ZSock::new_dealer("inproc://server_test_recv_chunk").unwrap();
        dealer.set_sndtimeo(Some(500));
        dealer.set_rcvtimeo(Some(500));
        let mut router = ZSock::new_router("inproc://server_test_recv_chunk").unwrap();
        router.set_sndtimeo(Some(500));
        router.set_rcvtimeo(Some(500));
        let mut router_dup = unsafe { ZSock::from_raw(router.as_mut_ptr(), false) };

        dealer.send_str("test").unwrap();
        let router_id = match ZFrame::recv(&mut router).unwrap().data().unwrap() {
            Ok(s) => s.into_bytes(),
            Err(b) => b,
        };
        router.flush();

        let mut server = new_server(router, true);

        let msg = ZMsg::new();
        msg.addstr("CHUNK").unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();

        let msg = ZMsg::recv(&mut dealer).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Err");
        assert_eq!(msg.popstr().unwrap().unwrap(), "Invalid request");

        let tempdir = TempDir::new("server_test_recv_chunk").unwrap();
        let file = File::create(&mut server.arbitrator, "abc".as_bytes(), &format!("{}/testfile", tempdir.path().to_str().unwrap()), 0, 0, 1, "{}").unwrap();
        server.files.insert(router_id, file);

        let msg = ZMsg::new();
        msg.addstr("CHUNK").unwrap();
        msg.addstr("1").unwrap();
        msg.addbytes("bytes".as_bytes()).unwrap();
        msg.send(&mut dealer).unwrap();

        server.recv(&mut router_dup).unwrap();

        let msg = ZMsg::recv(&mut dealer).unwrap();
        assert_eq!(msg.popstr().unwrap().unwrap(), "Err");
        assert_eq!(msg.popstr().unwrap().unwrap(), "Chunk index not in file");
    }

    #[test]
    fn test_recv_sink() {
        ZSys::init();

        let mut worker = ZSock::new_push("inproc://server_test_recv_sink").unwrap();
        let mut sink = ZSock::new_pull("inproc://server_test_recv_sink").unwrap();
        let mut sink_dup = unsafe { ZSock::from_raw(sink.as_mut_ptr(), false) };

        let mut server = new_server(sink, false);
        let tempdir = TempDir::new("server_test_recv_chunk").unwrap();
        let file = File::create(&mut server.arbitrator, "abc".as_bytes(), &format!("{}/testfile", tempdir.path().to_str().unwrap()), 1, 0, 1, "{}").unwrap();
        server.files.insert("abc".as_bytes().into(), file);

        let msg = ZMsg::new();
        msg.addstr("abc").unwrap();
        msg.addstr("0").unwrap();
        msg.addstr("1").unwrap();
        msg.send(&mut worker).unwrap();

        assert!(server.recv(&mut sink_dup).is_ok());
    }

    fn new_server(sock: ZSock, is_router: bool) -> Server {
        let router;
        let sink;
        if is_router {
            router = sock;
            sink = ZSock::new(SocketType::PULL);
        } else {
            router = ZSock::new(SocketType::ROUTER);
            sink = sock;
        }

        let (s_sock, a_sock) = ZSys::create_pipe().unwrap();
        let arbitrator = Arbitrator::new(a_sock, 0).unwrap();

        Server {
            router: router,
            sink: sink,
            files: HashMap::new(),
            arbitrator: arbitrator,
            arbitrator_sock: s_sock,
        }
    }
}
<|endoftext|>


<commit_before>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use std::fs;
use std::io::Read;
use std::path::Path;

pub use luminance::{ProgramError, Uniformable, UniformUpdate};
pub use luminance::shader::program::UniformWarning;
pub use luminance_gl::gl33::{self, Uniform};
pub use luminance_gl::gl33::token::*;

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: &GetUni) -> Result<gl33::Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          gl33::Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          gl33::Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else if let Some(gs) = gs {
        gl33::Program::new(None, &vs, Some(&gs), &fs, get_uni)
      } else {
        gl33::Program::new(None, &vs, None, &fs, get_uni)
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn new_program_from_disk<P, GetUni, T>(tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: &GetUni) -> Result<gl33::Program<T>, ProgramError>
      where P: AsRef<Path>,
            GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  // load vertex and fragment shaders first
  let vs = try!(read_stage(vs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
  let fs = try!(read_stage(fs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

  match (tess_path, gs_path) {
    (None, None) => { // no tessellation nor geometry
      gl33::Program::new(None, &vs, None, &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), None) => { // tessellation without geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      gl33::Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
    },
    (None, Some(gs_path)) => { // geometry without tessellation
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      gl33::Program::new(None, &vs, Some(&gs), &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), Some(gs_path)) => { // tessellation and geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      gl33::Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
    }
  }
}

pub fn read_stage<P, T>(path: P) -> Result<Stage<T>, StageError> where P: AsRef<Path>, T: ShaderTypeable {
  let path = path.as_ref();

  info!("loading {:?} stage: \x1b[35m{:?}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

#[cfg(feature = "hot-resource")]
mod hot {
  use super::*;

  use luminance_gl::gl33::ProgramProxy;
  use resource::ResourceManager;
  use std::ops::Deref;
  use std::path::{Path, PathBuf};
  use std::sync::mpsc;

  pub struct Program<T> {
    rx: mpsc::Receiver<()>,
    last_update_time: Option<f64>,
    program: gl33::Program<T>,
    get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError>>,
    vs_path: PathBuf,
    fs_path: PathBuf,
    tess_path: Option<(PathBuf, PathBuf)>,
    gs_path: Option<PathBuf>
  }

  impl<T> Program<T> {
    pub fn load<GetUni, P>(manager: &mut ResourceManager, tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Self, ProgramError>
        where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> + 'static,
              P: AsRef<Path> {
      let vs_path = vs_path.as_ref();
      let fs_path = fs_path.as_ref();
      let tess_path = tess_path.as_ref().map(|&(ref tcs, ref tes)| (tcs.as_ref(), tes.as_ref()));
      let gs_path = gs_path.as_ref().map(|gs| gs.as_ref());

      let program = try!(new_program_from_disk(tess_path, vs_path, gs_path, fs_path, &get_uni));

      let (sx, rx) = mpsc::channel();
      manager.monitor(vs_path, sx.clone());
      manager.monitor(fs_path, sx.clone());

      if let Some((tcs, tes)) = tess_path {
        manager.monitor(tcs, sx.clone());
        manager.monitor(tes, sx.clone());
      }

      if let Some(gs) = gs_path {
        manager.monitor(gs, sx.clone());
      }

      Ok(Program {
        rx: rx,
        last_update_time: None,
        program: program,
        get_uni: Box::new(get_uni),
        vs_path: vs_path.to_path_buf(),
        fs_path: fs_path.to_path_buf(),
        tess_path: tess_path.map(|(tcs, tes)| (tcs.to_path_buf(), tes.to_path_buf())),
        gs_path: gs_path.map(|gs| gs.to_path_buf()),
      })
    }

    fn reload(&mut self) {
      let vs = self.vs_path.as_path();
      let fs = self.fs_path.as_path();
      let tess = self.tess_path.as_ref().map(|&(ref tcs, ref tes)| (tcs.as_path(), tes.as_path()));
      let gs = self.gs_path.as_ref().map(|gs| gs.as_path());

      let program = new_program_from_disk(tess, vs, gs, fs, &self.get_uni.as_ref());

      match program {
        Ok(program) => {
          self.program = program;
          info!("reloaded shader program");
        },
        Err(e) => {
          err!("reloading program has failed: {:?}", e);
        }
      }
    }

    decl_sync_hot!();
  }

  impl<'a, T> Deref for Program<T> {
    type Target = gl33::Program<T>;

    fn deref(&self) -> &Self::Target {
      &self.program
    }
  }
}

#[cfg(not(feature = "hot-resource"))]
mod cold {
  use super::*;

  use luminance_gl::gl33::ProgramProxy;
  use resource::ResourceManager;
  use std::ops::Deref;
  use std::path::Path;

  pub struct Program<T>(gl33::Program<T>);

  impl<T> Program<T> {
    pub fn load<GetUni, P>(_: &mut ResourceManager, tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Program<T>, ProgramError>
        where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> + 'static,
              P: AsRef<Path> {
      let vs_path = vs_path.as_ref();
      let fs_path = fs_path.as_ref();
      let tess_path = tess_path.as_ref().map(|&(ref tcs, ref tes)| (tcs.as_ref(), tes.as_ref()));
      let gs_path = gs_path.as_ref().map(|gs| gs.as_ref());

      let program = try!(new_program_from_disk(tess_path, vs_path, gs_path, fs_path, &get_uni));

      Ok(Program(program))
    }

    pub fn sync(&mut self) {}
  }

  impl<'a, T> Deref for Program<T> {
    type Target = gl33::Program<T>;

    fn deref(&self) -> &Self::Target {
      &self.0
    }
  }
}

#[cfg(feature = "hot-resource")]
pub use self::hot::*;
#[cfg(not(feature = "hot-resource"))]
pub use self::cold::*;

/// A helper function used to make uniforms optionable. If there’s a warning, it’s printed out.
pub fn opt_uni<T>(uni: (Uniform<T>, Option<UniformWarning>)) -> Uniform<T> where T: Uniformable<GL33> {
  if let Some(warning) = uni.1 {
    warn!("{:?}", warning);
  }

  uni.0
}
<commit_msg>Uses format.<commit_after>use luminance::{FragmentShader, GeometryShader, StageError, ShaderTypeable,
                TessellationControlShader, TessellationEvaluationShader, VertexShader};
use luminance_gl::gl33::{ProgramProxy, Stage};
use std::fs;
use std::io::Read;
use std::path::Path;

pub use luminance::{ProgramError, Uniformable, UniformUpdate};
pub use luminance::shader::program::UniformWarning;
pub use luminance_gl::gl33::{self, Uniform};
pub use luminance_gl::gl33::token::*;

#[derive(Debug)]
pub enum ShaderError {
  StageError(StageError),
  ProgramError(ProgramError)
}

fn compile_stages(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str) -> Result<(Option<(Stage<TessellationControlShader>, Stage<TessellationEvaluationShader>)>, Stage<VertexShader>, Option<Stage<GeometryShader>>, Stage<FragmentShader>), StageError> {
  let tess = match tess_src {
    None => None,
    Some((tcs_src, tes_src)) => {
      let tcs = try!(Stage::new(tcs_src));
      let tes = try!(Stage::new(tes_src));
      Some((tcs, tes))
    }
  };
  let vs = try!(Stage::new(vs_src));
  let gs = match gs_src {
    None => None,
    Some(gs_src) => {
      let gs = try!(Stage::new(gs_src));
      Some(gs)
    }
  };
  let fs = try!(Stage::new(fs_src));

  Ok((tess, vs, gs, fs))
}

pub fn new_program<GetUni, T>(tess_src: Option<(&str, &str)>, vs_src: &str, gs_src: Option<&str>, fs_src: &str, get_uni: &GetUni) -> Result<gl33::Program<T>, ProgramError> where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  let stages = compile_stages(tess_src, vs_src, gs_src, fs_src);

  match stages {
    Ok((tess, vs, gs, fs)) => {
      if let Some((tcs, tes)) = tess {
        if let Some(gs) = gs {
          gl33::Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
        } else {
          gl33::Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
        }
      } else if let Some(gs) = gs {
        gl33::Program::new(None, &vs, Some(&gs), &fs, get_uni)
      } else {
        gl33::Program::new(None, &vs, None, &fs, get_uni)
      }
    },
    Err(stage_error) => {
      Err(ProgramError::LinkFailed(format!("{:?}", stage_error)))
    }
  }
}

pub fn new_program_from_disk<P, GetUni, T>(tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: &GetUni) -> Result<gl33::Program<T>, ProgramError>
      where P: AsRef<Path>,
            GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> {
  // load vertex and fragment shaders first
  let vs = try!(read_stage(vs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
  let fs = try!(read_stage(fs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));

  match (tess_path, gs_path) {
    (None, None) => { // no tessellation nor geometry
      gl33::Program::new(None, &vs, None, &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), None) => { // tessellation without geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      gl33::Program::new(Some((&tcs, &tes)), &vs, None, &fs, get_uni)
    },
    (None, Some(gs_path)) => { // geometry without tessellation
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      gl33::Program::new(None, &vs, Some(&gs), &fs, get_uni)
    },
    (Some((tcs_path, tes_path)), Some(gs_path)) => { // tessellation and geometry
      let tcs = try!(read_stage(tcs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let tes = try!(read_stage(tes_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      let gs = try!(read_stage(gs_path).map_err(|e| ProgramError::LinkFailed(format!("{:?}", e))));
      gl33::Program::new(Some((&tcs, &tes)), &vs, Some(&gs), &fs, get_uni)
    }
  }
}

pub fn read_stage<P, T>(path: P) -> Result<Stage<T>, StageError> where P: AsRef<Path>, T: ShaderTypeable {
  let path = path.as_ref();

  info!("loading {:?} stage: \x1b[35m{:?}", T::shader_type(), path);

  let fh = fs::File::open(path);

  match fh {
    Err(e) => {
      Err(StageError::CompilationFailed(T::shader_type(), format!("{:?}", e)))
    },
    Ok(mut fh) => {
      let mut stage_src = String::new();
      let _ = fh.read_to_string(&mut stage_src);

      Stage::new(stage_src.chars().as_str())
    }
  }
}

#[cfg(feature = "hot-resource")]
mod hot {
  use luminance_gl::gl33::ProgramProxy;
  use std::ops::Deref;
  use std::path::{Path, PathBuf};
  use std::sync::mpsc;

  use resource::ResourceManager;

  use super::*;

  pub struct Program<T> {
    rx: mpsc::Receiver<()>,
    last_update_time: Option<f64>,
    program: gl33::Program<T>,
    get_uni: Box<Fn(ProgramProxy) -> Result<T, ProgramError>>,
    vs_path: PathBuf,
    fs_path: PathBuf,
    tess_path: Option<(PathBuf, PathBuf)>,
    gs_path: Option<PathBuf>
  }

  impl<T> Program<T> {
    pub fn load<GetUni, P>(manager: &mut ResourceManager, tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Self, ProgramError>
        where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> + 'static,
              P: AsRef<Path> {
      let vs_path = vs_path.as_ref();
      let fs_path = fs_path.as_ref();
      let tess_path = tess_path.as_ref().map(|&(ref tcs, ref tes)| (tcs.as_ref(), tes.as_ref()));
      let gs_path = gs_path.as_ref().map(|gs| gs.as_ref());

      let program = try!(new_program_from_disk(tess_path, vs_path, gs_path, fs_path, &get_uni));

      let (sx, rx) = mpsc::channel();
      manager.monitor(vs_path, sx.clone());
      manager.monitor(fs_path, sx.clone());

      if let Some((tcs, tes)) = tess_path {
        manager.monitor(tcs, sx.clone());
        manager.monitor(tes, sx.clone());
      }

      if let Some(gs) = gs_path {
        manager.monitor(gs, sx.clone());
      }

      Ok(Program {
        rx: rx,
        last_update_time: None,
        program: program,
        get_uni: Box::new(get_uni),
        vs_path: vs_path.to_path_buf(),
        fs_path: fs_path.to_path_buf(),
        tess_path: tess_path.map(|(tcs, tes)| (tcs.to_path_buf(), tes.to_path_buf())),
        gs_path: gs_path.map(|gs| gs.to_path_buf()),
      })
    }

    fn reload(&mut self) {
      let vs = self.vs_path.as_path();
      let fs = self.fs_path.as_path();
      let tess = self.tess_path.as_ref().map(|&(ref tcs, ref tes)| (tcs.as_path(), tes.as_path()));
      let gs = self.gs_path.as_ref().map(|gs| gs.as_path());

      let program = new_program_from_disk(tess, vs, gs, fs, &self.get_uni.as_ref());

      match program {
        Ok(program) => {
          self.program = program;
          info!("reloaded shader program");
        },
        Err(e) => {
          err!("reloading program has failed: {:?}", e);
        }
      }
    }

    decl_sync_hot!();
  }

  impl<'a, T> Deref for Program<T> {
    type Target = gl33::Program<T>;

    fn deref(&self) -> &Self::Target {
      &self.program
    }
  }
}

#[cfg(not(feature = "hot-resource"))]
mod cold {
  use super::*;

  use luminance_gl::gl33::ProgramProxy;
  use resource::ResourceManager;
  use std::ops::Deref;
  use std::path::Path;

  pub struct Program<T>(gl33::Program<T>);

  impl<T> Program<T> {
    pub fn load<GetUni, P>(_: &mut ResourceManager, tess_path: Option<(P, P)>, vs_path: P, gs_path: Option<P>, fs_path: P, get_uni: GetUni) -> Result<Program<T>, ProgramError>
        where GetUni: Fn(ProgramProxy) -> Result<T, ProgramError> + 'static,
              P: AsRef<Path> {
      let vs_path = vs_path.as_ref();
      let fs_path = fs_path.as_ref();
      let tess_path = tess_path.as_ref().map(|&(ref tcs, ref tes)| (tcs.as_ref(), tes.as_ref()));
      let gs_path = gs_path.as_ref().map(|gs| gs.as_ref());

      let program = try!(new_program_from_disk(tess_path, vs_path, gs_path, fs_path, &get_uni));

      Ok(Program(program))
    }

    pub fn sync(&mut self) {}
  }

  impl<'a, T> Deref for Program<T> {
    type Target = gl33::Program<T>;

    fn deref(&self) -> &Self::Target {
      &self.0
    }
  }
}

#[cfg(feature = "hot-resource")]
pub use self::hot::*;
#[cfg(not(feature = "hot-resource"))]
pub use self::cold::*;

/// A helper function used to make uniforms optionable. If there’s a warning, it’s printed out.
pub fn opt_uni<T>(uni: (Uniform<T>, Option<UniformWarning>)) -> Uniform<T> where T: Uniformable<GL33> {
  if let Some(warning) = uni.1 {
    warn!("{:?}", warning);
  }

  uni.0
}
<|endoftext|>


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

//! Module containing `TaskStatus` type and trait impls

use std::fmt::{Display, Formatter, Error as FmtError};

/// Enum for status taskwarrior supports.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum TaskStatus {
    /// Pening status type
    Pending,

    /// Deleted status type
    Deleted,

    /// Completed status type
    Completed,

    /// Waiting status type
    Waiting,

    /// Recurring status type
    Recurring
}

impl Display for TaskStatus {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        match self {
            &TaskStatus::Pending   => write!(fmt, "Pending"),
            &TaskStatus::Deleted   => write!(fmt, "Deleted"),
            &TaskStatus::Completed => write!(fmt, "Completed"),
            &TaskStatus::Waiting   => write!(fmt, "Waiting"),
            &TaskStatus::Recurring => write!(fmt, "Recurring"),
        }
    }
}

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

//! Module containing `TaskStatus` type and trait impls

use std::fmt::{Display, Formatter, Error as FmtError};

/// Enum for status taskwarrior supports.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum TaskStatus {
    /// Pening status type
    #[serde(rename = "pending")]
    Pending,

    /// Deleted status type
    #[serde(rename = "deleted")]
    Deleted,

    /// Completed status type
    #[serde(rename = "completed")]
    Completed,

    /// Waiting status type
    #[serde(rename = "waiting")]
    Waiting,

    /// Recurring status type
    #[serde(rename = "recurring")]
    Recurring
}

impl Display for TaskStatus {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        match self {
            &TaskStatus::Pending   => write!(fmt, "Pending"),
            &TaskStatus::Deleted   => write!(fmt, "Deleted"),
            &TaskStatus::Completed => write!(fmt, "Completed"),
            &TaskStatus::Waiting   => write!(fmt, "Waiting"),
            &TaskStatus::Recurring => write!(fmt, "Recurring"),
        }
    }
}

<|endoftext|>