<commit_before>extern crate rand;

use self::rand::{thread_rng,Rng};

use std::collections::HashMap;
use std::sync::{Arc,RwLock,Mutex,mpsc};

use super::libcoinche::{bid,cards,pos,game};

pub enum ServerError {
    BadPlayerId,
    BadEventId,
    PlayInAuction,
    BidInGame,
    Bid(bid::BidError),
    Play(game::PlayError),
}

pub enum Action {
    Bid(bid::Contract),
    Coinche,
    Pass,
    Play(cards::Card),
}

#[derive(Clone)]
pub enum PlayerEvent {
    Bidded(bid::Contract),
    Coinched,
    Passed,
    CardPlayed(cards::Card),
}

// Player just joined a new party. He's given a player id, and his position.
pub struct NewPartyInfo {
    pub player_id: u32,
    pub player_pos: pos::PlayerPos,
}

// Represents an event that can happen during the game.
#[derive(Clone)]
pub enum EventType {
    // The party is cancelled. Contains an optional explanation.
    PartyCancelled(String),

    // A player did something!
    FromPlayer(pos::PlayerPos, PlayerEvent),

    // Bid over: contains the contract and the author
    BidOver(pos::PlayerPos, bid::Contract),
    // The bid was cancelled, probably because no one bidded anything.
    // A new game is probably on its way.
    BidCancelled,

    // Trick over: contains the winner
    TrickOver(pos::PlayerPos),

    // New game: contains the first player, and the player's hand
    NewGame(pos::PlayerPos, [cards::Hand;4]),

    // Game over: contains scores
    GameOver([i32;2], pos::Team, [i32;2]),
}

#[derive(Clone)]
pub struct Event {
    pub event: EventType,
    pub id: usize,
}

pub struct Order {
    pub author: pos::PlayerPos,
    pub action: Action
}

pub struct Server {
    party_list: RwLock<PartyList>,

    waiting_list: Mutex<Vec<mpsc::Sender<NewPartyInfo>>>,
}

pub enum Game {
    Bidding(bid::Auction),
    Playing(game::GameState),
}

pub struct Party {
    game: Game,
    events: Vec<EventType>,
    observers: Vec<mpsc::Sender<Event>>,
}

fn new_party(first: pos::PlayerPos) -> Party {
    Party {
        game: Game::Bidding(bid::new_auction(first)),
        events: Vec::new(),
        observers: Vec::new(),
    }
}

impl Party {
    fn add_event(&mut self, event: EventType) {
        let ev = Event{
            event: event.clone(),
            id: self.events.len(),
        };
        for sender in self.observers.iter() {
            sender.send(ev.clone()).unwrap();
        }
        self.observers.clear();
        self.events.push(event);
    }
}

pub struct PlayerInfo {
    pub party: Arc<RwLock<Party>>,
    pub pos: pos::PlayerPos,
}

pub struct PartyList {
    pub player_map: HashMap<u32,PlayerInfo>,
}

impl PartyList {
    fn make_ids(&self) -> [u32; 4] {
        // Expect self.player_map to be locked
        let mut result = [0;4];

        for i in 0..4 {
            loop {
                let id = thread_rng().next_u32();
                if self.player_map.contains_key(&id) {
                    continue;
                }
                let mut ok = true;
                for j in 0..i {
                    if result[j] == id {
                        ok = false;
                        break;
                    }
                }
                if !ok {
                    continue;
                }

                result[i] = id;
            }
        }

        result
    }
}

enum WaitResult {
    Ready(Event),
    Waiting(mpsc::Receiver<Event>),
}

enum JoinResult {
    Ready(NewPartyInfo),
    Waiting(mpsc::Receiver<NewPartyInfo>),
}

impl Server {
    pub fn join(&self) -> Option<NewPartyInfo> {
        match self.get_join_result() {
            JoinResult::Ready(info) => Some(info),
            JoinResult::Waiting(rx) => Some(rx.recv().unwrap()),
        }
    }

    fn get_join_result(&self) -> JoinResult {
        let mut waiters = self.waiting_list.lock().unwrap();
        if waiters.len() >= 3 {
            // It's a PARTEY!
            let info = self.make_party([
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
            ]);
            return JoinResult::Ready(info);
        } else {
            let (tx,rx) = mpsc::channel();
            waiters.push(tx);
            return JoinResult::Waiting(rx);
        }
    }

    fn make_party(&self, others: [mpsc::Sender<NewPartyInfo>; 3]) -> NewPartyInfo {
        let mut list = self.party_list.write().unwrap();

        // Generate 4 new IDS
        let ids = list.make_ids();

        let party = Arc::new(RwLock::new(new_party(pos::P0)));
        // Kickstart it with a new game!

        // Prepare the players info
        for i in 0..4 {
            list.player_map.insert(ids[i], PlayerInfo {
                party: party.clone(),
                pos: pos::PlayerPos(i),
            });
        }

        // Tell everyone. They'll love it.
        for i in 0..3 {
            others[i].send(NewPartyInfo{
                player_id: ids[i],
                player_pos: pos::PlayerPos(i),
            }).unwrap();
        }

        // Even you, weird 4th dude.
        NewPartyInfo{
            player_id: ids[3],
            player_pos: pos::P3,
        }
    }

    // Play a card in the current game
    pub fn play_card(&self, player_id: u32, card: cards::Card) -> Result<Event,ServerError> {
        let list = self.party_list.read().unwrap();

        if !list.player_map.contains_key(&player_id) {
            // Bad player id!

            return Err(ServerError::BadPlayerId);
        }

        let info = list.player_map.get(&player_id).unwrap();

        let mut party = info.party.write().unwrap();

        let result = match &mut party.game {
            &mut Game::Bidding(_) => {
                // Bad time for a card play!
                return Err(ServerError::PlayInAuction);
            },
            &mut Game::Playing(ref mut game) => {
                match game.play_card(info.pos, card) {
                    Ok(result) => result,
                    Err(err) => {
                        // Nothing to see here
                        return Err(ServerError::Play(err));
                    },
                }
            },
        };
        party.add_event(EventType::FromPlayer(info.pos, PlayerEvent::CardPlayed(card)));
        match result {
            game::TrickResult::Nothing => (),
            game::TrickResult::TrickOver(winner) => party.add_event(EventType::TrickOver(winner)),
        }

        // TODO: check for gameover?

        // Dummy event before handling the real case
        Ok(Event{
            event: EventType::BidCancelled,
            id:0
        })
    }

    // TODO: add bidding and stuff?

    // Waits until the given event_id happens
    pub fn wait(&self, player_id: u32, event_id: usize) -> Result<Event,ServerError> {
        let res = self.get_wait_result(player_id, event_id);

        match res {
            Err(err) => Err(err),
            Ok(WaitResult::Ready(event)) => Ok(event),
            // TODO: handle case where the wait is cancelled
            // (don't unwrap, return an error instead?)
            Ok(WaitResult::Waiting(rx)) => Ok(rx.recv().unwrap()),
        }
    }

    // Check if the event ID is already available. If not, returns a channel that will produce it one
    // day, so that we don't keep the locks while waiting.
    fn get_wait_result(&self, player_id: u32, event_id: usize) -> Result<WaitResult,ServerError> {
        let list = self.party_list.read().unwrap();
        if !list.player_map.contains_key(&player_id) {
            return Err(ServerError::BadPlayerId);
        }

        let info = list.player_map.get(&player_id).unwrap();
        let mut party = info.party.write().unwrap();

        if party.events.len() > event_id {
            return Ok(WaitResult::Ready(Event {
                event: party.events[event_id].clone(),
                id: event_id,
            }));
        } else if event_id > party.events.len() {
            // We are too ambitious! One event at a time!
            return Err(ServerError::BadEventId);
        }

        let (tx, rx) = mpsc::channel();
        party.observers.push(tx);

        Ok(WaitResult::Waiting(rx))
    }
}

<commit_msg>Clearer map access<commit_after>extern crate rand;

use self::rand::{thread_rng,Rng};

use std::collections::HashMap;
use std::sync::{Arc,RwLock,Mutex,mpsc};

use super::libcoinche::{bid,cards,pos,game};

pub enum ServerError {
    BadPlayerId,
    BadEventId,
    PlayInAuction,
    BidInGame,
    Bid(bid::BidError),
    Play(game::PlayError),
}

pub enum Action {
    Bid(bid::Contract),
    Coinche,
    Pass,
    Play(cards::Card),
}

#[derive(Clone)]
pub enum PlayerEvent {
    Bidded(bid::Contract),
    Coinched,
    Passed,
    CardPlayed(cards::Card),
}

// Player just joined a new party. He's given a player id, and his position.
pub struct NewPartyInfo {
    pub player_id: u32,
    pub player_pos: pos::PlayerPos,
}

// Represents an event that can happen during the game.
#[derive(Clone)]
pub enum EventType {
    // The party is cancelled. Contains an optional explanation.
    PartyCancelled(String),

    // A player did something!
    FromPlayer(pos::PlayerPos, PlayerEvent),

    // Bid over: contains the contract and the author
    BidOver(pos::PlayerPos, bid::Contract),
    // The bid was cancelled, probably because no one bidded anything.
    // A new game is probably on its way.
    BidCancelled,

    // Trick over: contains the winner
    TrickOver(pos::PlayerPos),

    // New game: contains the first player, and the player's hand
    NewGame(pos::PlayerPos, [cards::Hand;4]),

    // Game over: contains scores
    GameOver([i32;2], pos::Team, [i32;2]),
}

#[derive(Clone)]
pub struct Event {
    pub event: EventType,
    pub id: usize,
}

pub struct Order {
    pub author: pos::PlayerPos,
    pub action: Action
}

pub struct Server {
    party_list: RwLock<PartyList>,

    waiting_list: Mutex<Vec<mpsc::Sender<NewPartyInfo>>>,
}

pub enum Game {
    Bidding(bid::Auction),
    Playing(game::GameState),
}

pub struct Party {
    game: Game,
    events: Vec<EventType>,
    observers: Vec<mpsc::Sender<Event>>,
}

fn new_party(first: pos::PlayerPos) -> Party {
    Party {
        game: Game::Bidding(bid::new_auction(first)),
        events: Vec::new(),
        observers: Vec::new(),
    }
}

impl Party {
    fn add_event(&mut self, event: EventType) {
        let ev = Event{
            event: event.clone(),
            id: self.events.len(),
        };
        for sender in self.observers.iter() {
            sender.send(ev.clone()).unwrap();
        }
        self.observers.clear();
        self.events.push(event);
    }
}

pub struct PlayerInfo {
    pub party: Arc<RwLock<Party>>,
    pub pos: pos::PlayerPos,
}

pub struct PartyList {
    pub player_map: HashMap<u32,PlayerInfo>,
}

impl PartyList {
    fn make_ids(&self) -> [u32; 4] {
        // Expect self.player_map to be locked
        let mut result = [0;4];

        for i in 0..4 {
            loop {
                let id = thread_rng().next_u32();
                if self.player_map.contains_key(&id) {
                    continue;
                }
                let mut ok = true;
                for j in 0..i {
                    if result[j] == id {
                        ok = false;
                        break;
                    }
                }
                if !ok {
                    continue;
                }

                result[i] = id;
            }
        }

        result
    }
}

enum WaitResult {
    Ready(Event),
    Waiting(mpsc::Receiver<Event>),
}

enum JoinResult {
    Ready(NewPartyInfo),
    Waiting(mpsc::Receiver<NewPartyInfo>),
}

impl Server {
    pub fn join(&self) -> Option<NewPartyInfo> {
        match self.get_join_result() {
            JoinResult::Ready(info) => Some(info),
            JoinResult::Waiting(rx) => Some(rx.recv().unwrap()),
        }
    }

    fn get_join_result(&self) -> JoinResult {
        let mut waiters = self.waiting_list.lock().unwrap();
        if waiters.len() >= 3 {
            // It's a PARTEY!
            let info = self.make_party([
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
                                       waiters.pop().unwrap(),
            ]);
            return JoinResult::Ready(info);
        } else {
            let (tx,rx) = mpsc::channel();
            waiters.push(tx);
            return JoinResult::Waiting(rx);
        }
    }

    fn make_party(&self, others: [mpsc::Sender<NewPartyInfo>; 3]) -> NewPartyInfo {
        let mut list = self.party_list.write().unwrap();

        // Generate 4 new IDS
        let ids = list.make_ids();

        let party = Arc::new(RwLock::new(new_party(pos::P0)));
        // Kickstart it with a new game!

        // Prepare the players info
        for i in 0..4 {
            list.player_map.insert(ids[i], PlayerInfo {
                party: party.clone(),
                pos: pos::PlayerPos(i),
            });
        }

        // Tell everyone. They'll love it.
        for i in 0..3 {
            others[i].send(NewPartyInfo{
                player_id: ids[i],
                player_pos: pos::PlayerPos(i),
            }).unwrap();
        }

        // Even you, weird 4th dude.
        NewPartyInfo{
            player_id: ids[3],
            player_pos: pos::P3,
        }
    }

    // Play a card in the current game
    pub fn play_card(&self, player_id: u32, card: cards::Card) -> Result<Event,ServerError> {
        let list = self.party_list.read().unwrap();

        let info = match list.player_map.get(&player_id) {
            Some(info) => info,
            None => return Err(ServerError::BadPlayerId),
        };

        let mut party = info.party.write().unwrap();

        let result = match &mut party.game {
            &mut Game::Bidding(_) => {
                // Bad time for a card play!
                return Err(ServerError::PlayInAuction);
            },
            &mut Game::Playing(ref mut game) => {
                match game.play_card(info.pos, card) {
                    Ok(result) => result,
                    Err(err) => {
                        // Nothing to see here
                        return Err(ServerError::Play(err));
                    },
                }
            },
        };
        party.add_event(EventType::FromPlayer(info.pos, PlayerEvent::CardPlayed(card)));
        match result {
            game::TrickResult::Nothing => (),
            game::TrickResult::TrickOver(winner) => party.add_event(EventType::TrickOver(winner)),
        }

        // TODO: check for gameover?

        // Dummy event before handling the real case
        Ok(Event{
            event: EventType::BidCancelled,
            id:0
        })
    }

    // TODO: add bidding and stuff?

    // Waits until the given event_id happens
    pub fn wait(&self, player_id: u32, event_id: usize) -> Result<Event,ServerError> {
        let res = self.get_wait_result(player_id, event_id);

        match res {
            Err(err) => Err(err),
            Ok(WaitResult::Ready(event)) => Ok(event),
            // TODO: handle case where the wait is cancelled
            // (don't unwrap, return an error instead?)
            Ok(WaitResult::Waiting(rx)) => Ok(rx.recv().unwrap()),
        }
    }

    // Check if the event ID is already available. If not, returns a channel that will produce it one
    // day, so that we don't keep the locks while waiting.
    fn get_wait_result(&self, player_id: u32, event_id: usize) -> Result<WaitResult,ServerError> {
        let list = self.party_list.read().unwrap();

        let info = match list.player_map.get(&player_id) {
            Some(info) => info,
            None => return Err(ServerError::BadPlayerId),
        };

        let mut party = info.party.write().unwrap();

        if party.events.len() > event_id {
            return Ok(WaitResult::Ready(Event {
                event: party.events[event_id].clone(),
                id: event_id,
            }));
        } else if event_id > party.events.len() {
            // We are too ambitious! One event at a time!
            return Err(ServerError::BadEventId);
        }

        let (tx, rx) = mpsc::channel();
        party.observers.push(tx);

        Ok(WaitResult::Waiting(rx))
    }
}

<|endoftext|>


<commit_before>use std::comm::{Receiver, Sender};
use uuid::Uuid;
use std::io::timer::Timer;
use std::time::duration::Duration;

use addr::Addr;
use broadcast::Broadcast;
use result::{GossipResult, GossipError};

use node::Node;
use health::{Health};
use state::State;

/// Each shutdown command needs to have a reason. Sometimes, we may not know the reason
/// of a particular shutdown (the network may fail, but we don't know if it's them or us, etc...).
/// This also improves error handling and error reporting to where it allows one to report the type
/// of shutdown and when.
#[deriving(Show, PartialEq)]
pub enum ShutdownReason {
    UserInitiatedShutdown,
    NetworkFailure,
    Failure
}

/// Current status of a particular server.
#[deriving(Show, PartialEq, Clone)]
pub enum Status {
    Initializing,
    Running,
    ShuttingDown,
    Failing
}

/// All the possible types of messages we can send to most of the channels that communicate with
/// the server. The most common one is the `Message` variant, which initiates/receives a new
/// broadcast/gossip to the appropriate nodes.
#[deriving(Show, PartialEq)]
pub enum ServerMessage {
    /// A broadcast/gossip that can be sent and/or received!
    Message(Broadcast),
    /// A shutdown command to the local node. This is an internal variant and thus isn't used
    /// to kill another member within the cluster. If we have received one of those commands, then
    /// this is emitted internally.
    Shutdown(ShutdownReason),
}

/// Handle the communication and setup of the server. Each server is spawned on
/// a separate task for isolation and independence. Thus, the only communication mechanism
/// is through the use of channels. Instead of requiring the user of the crate to initialize
/// all the local channels and such, this handles it automatically resulting in a super
/// clean API.
pub struct Server {
    /// Part of a channel that the server sends messages to.
    receiver: Receiver<ServerMessage>,
    /// Part of a channel that communicates with the server.
    sender: Sender<ServerMessage>
}

impl Server {
    /// Create a new `Server` that will handle the initialization of
    /// a server in a separate task. This will also handle creating all the required
    /// channels and such.
    ///
    /// ```rust
    /// use gossip::{Server};
    ///
    /// let mut server = Server::create("127.0.0.1", 4555);
    ///
    /// // We need to shutdown the system so that we don't hang in the
    /// // tests.
    /// server.shutdown();
    /// ```
    pub fn create(ip: &str, port: u16) -> Server {
        // Create an intermediate channel to send and receive another Sender
        // that will be used in the `Server`. This channel is only used
        // once and then thrown away.
        let (tx, rx) = channel();

        // Create another channel that will act as the local receiver. The sender
        // will be sent to the server.
        let (sender, receiver) = channel();

        // A slice does not implement `Send` so we have to allocate it first.
        let addr = ip.to_string();

        spawn(proc() {
            // Create a new server sending our `Sender`. This allows the server to send the user
            // messages over the channel.
            let mut server = InternalServer::new(sender.clone());

            // Send back the server's sender portion of the channel. This is how
            // we can further communicate with the server.
            tx.send(server.sender.clone());

            // Start the server. This will run forever until it's killed.
            server.listen(addr.as_slice(), port).unwrap();
        });

        Server {
            receiver: receiver,
            sender: rx.recv()
        }
    }

    /// Call the shutdown method after a set duration. This uses a
    /// synchronous timer.
    pub fn shutdown_in(&mut self, time: Duration) {
        let mut timer = Timer::new().unwrap();
        timer.sleep(time);
        self.shutdown();
    }

    /// Shutdown the current server now. This may not happen right away,
    /// but as soon as the proper protocol has been followed.
    pub fn shutdown(&mut self) {
        self.sender.send(Shutdown(UserInitiatedShutdown));
    }

    /// A slightly nicer interface for sending messages to the Server. This
    /// allows us to keep the `receiver` and `sender` private.
    pub fn recv(&mut self) -> ServerMessage {
        self.receiver.recv()
    }
}

/// A server/node/peer is the most atomic unit within a cluster. Each node is equal with it's peers,
/// thus we don't have any leader or election processes. Each server is identified with a unique ID
/// that is randomly generated, along with the appropriate state.
///
/// A server requires a bit of metadata about the cluster, the cluster's state and things like
/// channels. Each server has it's own Receiver to handle incoming messages. A separate Receiver
/// is used for users of this library. We then have a Sender that sends to the server's receiver.
/// This is meant to be copied to the appropriate task.
///
/// Usage:
///
/// ```rust
/// use gossip::{InternalServer, Shutdown};
/// use std::time::duration::Duration;
///
/// let mut server = InternalServer::create("127.0.0.1", 5666);
///
/// // Shutdown in the specified time in seconds.
/// server.shutdown_in(Duration::seconds(1));
///
/// // Wait for new messages. This will block the main task until the
/// // server has been shutdown.
/// loop {
///     match server.recv() {
///         Shutdown(reason) => break,
///         _ => {}
///     }
/// }
/// ```
pub struct InternalServer {
    /// A unique id for the server. This allows servers to talk about each other in
    /// a consistent manner.
    id: Uuid,
    /// The server may have an address to bind to. We make it optional to have a cleaner API
    /// to initially create the server, as the address is only needed at the .listen method.
    addr: Option<Addr>,
    /// Keep track of the server's status so that operations can be applied or rejected depending
    /// on which status it's current set on. This allows us to track whether the server
    /// has already initiated a shutdown or whether it's still running.
    status: Status,
    /// The state handles the core Gossip protocol. It's basically a giant state machine
    /// that keeps track of which nodes to communicate with, which nodes are alive/dead/failing,
    /// etc...
    state: State,
    /// A collection of servers within the cluster. Note that these aren't allocated/running
    /// servers, so we use another record called `Node` to handle that understanding.
    servers: Vec<Node>,
    /// The internal receiver to handle incoming messages. These can be messages coming from a
    /// transport, or from a user.
    receiver: Receiver<ServerMessage>,
    /// The sender-half of the previous channel. This is copied to the user and transports to send
    /// incoming messages. These aren't always broadcasts! Broadcasts are simply one kind of server
    /// message.
    sender: Sender<ServerMessage>,
    /// This is the user sender so that we can communicate with the end user of this crate. Any
    /// broadcasts that we don't handle will be relayed to the user's sender and they can take
    /// care of it.
    tx: Sender<ServerMessage>
}

impl InternalServer {

    /// Create a standard, default server. This only initializes the server
    /// but does **not** start it! So it doesn't spawn a new thread.
    ///
    /// This function requires a Sender so that the server can relay messages
    /// externally (such as the user of the crate).
    pub fn new(sender: Sender<ServerMessage>) -> InternalServer {
        // Create an internal channel for the server. The sender is often
        // copied around to various components.
        let (tx, rx) = channel();

        InternalServer {
            id: Uuid::new_v4(),
            addr: None,
            status: Initializing,
            state: State::new(),
            servers: Vec::new(),
            receiver: rx,
            sender: tx,
            tx: sender
        }
    }

    /// Create a new `Server` that is responsible for fully initializing and starting
    /// the server component. A `Server` is what the user will interact with as the server
    /// is running within another task, so the communication protocol is through channels
    /// exclusively.
    pub fn create(ip: &str, port: u16) -> Server {
        Server::create(ip, port)
    }

    /// Bind the server to the specified address. If there's a transport,
    /// it has the possibility of failing.
    pub fn listen(&mut self, ip: &str, port: u16) -> GossipResult<()> {
        self.addr = Some(Addr::new(ip, port));
        self.status = Running;

        // FIXME: We'll probably need a select! macro invocation to allow the ability
        // to read from multiple sources.
        loop {
            // Receive the next message from the channel. This can be from any component.
            match self.receiver.recv() {
                // Ok, so we are tasked with shutting down. We'll relay the shutdown
                // message back to the user so they can do some cleanup or other operations.
                //
                // FIXME: We'll need to broadcast to the cluster that this server is shutting down.
                Shutdown(reason) => {
                    self.tx.send(Shutdown(reason));
                    break;
                },
                _ => {}
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{Arc, Mutex};

    #[test]
    fn default_server() {
        let (tx, rx) = channel();
        let s = InternalServer::new(tx);
        assert!(s.addr.is_none())
        assert_eq!(s.status, Initializing);
    }

    #[test]
    fn server_access_with_mutex() {
        let (tx, rx) = channel();

        // Create the task local mutex.
        let mutex = Arc::new(Mutex::new(InternalServer::new(tx)));

        // Copy the mutex (through the Arc) for use in another task.
        let mutex2 = mutex.clone();

        // We need to get the sender from the server.
        let mut val = mutex.lock();
        let sender = (*val).sender.clone();

        // Release the mutex.
        drop(val);

        spawn(proc() {
            let mut val = mutex2.lock();
            val.listen("127.0.0.1", 8777);
        });

        // Shutdown the server so we can finish the test.
        sender.send(Shutdown(UserInitiatedShutdown));

        match rx.recv() {
            Shutdown(reason) if reason == UserInitiatedShutdown => {
                assert!(true);
            },
            _ => fail!("Unexpected output")
        }
    }

    #[test]
    fn shutdown_server() {
        let (tx, rx) = channel();
        let mut s = InternalServer::new(tx);

        s.sender.send(Shutdown(UserInitiatedShutdown));
    }
}
<commit_msg>Added a get_status method<commit_after>use std::comm::{Receiver, Sender};
use uuid::Uuid;
use std::io::timer::Timer;
use std::time::duration::Duration;

use addr::Addr;
use broadcast::Broadcast;
use result::{GossipResult, GossipError};

use node::Node;
use health::{Health};
use state::State;

/// Each shutdown command needs to have a reason. Sometimes, we may not know the reason
/// of a particular shutdown (the network may fail, but we don't know if it's them or us, etc...).
/// This also improves error handling and error reporting to where it allows one to report the type
/// of shutdown and when.
#[deriving(Show, PartialEq)]
pub enum ShutdownReason {
    UserInitiatedShutdown,
    NetworkFailure
}

/// Current status of a particular server.
#[deriving(Show, PartialEq, Clone)]
pub enum Status {
    Initializing,
    Running,
    ShuttingDown,
    Failing
}

#[deriving(Show, PartialEq)]
pub enum FailureKind {
    BroadcastFailed
}

#[deriving(Show, PartialEq)]
pub enum QueryType {
    StatusQuery
}

#[deriving(Show, PartialEq)]
pub enum QueryResponseType {
    StatusQueryResponse(Status)
}

/// All the possible types of messages we can send to most of the channels that communicate with
/// the server. The most common one is the `Message` variant, which initiates/receives a new
/// broadcast/gossip to the appropriate nodes.
#[deriving(Show, PartialEq)]
pub enum ServerMessage {
    /// A broadcast/gossip that can be sent and/or received!
    Message(Broadcast),
    /// A shutdown command to the local node. This is an internal variant and thus isn't used
    /// to kill another member within the cluster. If we have received one of those commands, then
    /// this is emitted internally.
    Shutdown(ShutdownReason),
    Failure(FailureKind),
    Query(QueryType),
    QueryResponse(QueryResponseType)
}

/// Handle the communication and setup of the server. Each server is spawned on
/// a separate task for isolation and independence. Thus, the only communication mechanism
/// is through the use of channels. Instead of requiring the user of the crate to initialize
/// all the local channels and such, this handles it automatically resulting in a super
/// clean API.
pub struct Server {
    /// Part of a channel that the server sends messages to.
    receiver: Receiver<ServerMessage>,
    /// Part of a channel that communicates with the server.
    sender: Sender<ServerMessage>,
    /// A buffer of messages that we have gotten, but need to collect before reading them
    /// later on.
    buffer: Vec<ServerMessage>
}

impl Server {
    /// Create a new `Server` that will handle the initialization of
    /// a server in a separate task. This will also handle creating all the required
    /// channels and such.
    ///
    /// ```rust
    /// use gossip::{Server};
    ///
    /// let mut server = Server::create("127.0.0.1", 4555);
    ///
    /// // We need to shutdown the system so that we don't hang in the
    /// // tests.
    /// server.shutdown();
    /// ```
    pub fn create(ip: &str, port: u16) -> Server {
        // Create an intermediate channel to send and receive another Sender
        // that will be used in the `Server`. This channel is only used
        // once and then thrown away.
        let (tx, rx) = channel();

        // Create another channel that will act as the local receiver. The sender
        // will be sent to the server.
        let (sender, receiver) = channel();

        // A slice does not implement `Send` so we have to allocate it first.
        let addr = ip.to_string();

        spawn(proc() {
            // Create a new server sending our `Sender`. This allows the server to send the user
            // messages over the channel.
            let mut server = InternalServer::new(sender.clone());

            // Send back the server's sender portion of the channel. This is how
            // we can further communicate with the server.
            tx.send(server.sender.clone());

            // Start the server. This will run forever until it's killed.
            server.listen(addr.as_slice(), port).unwrap();
        });

        Server {
            receiver: receiver,
            sender: rx.recv(),
            buffer: Vec::new()
        }
    }

    /// Call the shutdown method after a set duration. This uses a
    /// synchronous timer.
    pub fn shutdown_in(&mut self, time: Duration) {
        let mut timer = Timer::new().unwrap();
        timer.sleep(time);
        self.shutdown();
    }

    /// Shutdown the current server now. This may not happen right away,
    /// but as soon as the proper protocol has been followed.
    pub fn shutdown(&mut self) {
        self.sender.send(Shutdown(UserInitiatedShutdown));
    }

    /// A slightly nicer interface for sending messages to the Server. This
    /// allows us to keep the `receiver` and `sender` private.
    pub fn recv(&mut self) -> ServerMessage {
        self.receiver.recv()
    }

    pub fn broadcast(&mut self, broadcast: Broadcast) {
        //self.sender.send(Message(broadcast));
    }

    /// Send the server a request to send back the current status. This is used
    /// to determine at what stage the server is at. Whether it's running or not.
    pub fn get_status(&mut self) -> Status {
        self.sender.send(Query(StatusQuery));

        loop {
            match self.recv() {
                QueryResponse(StatusQueryResponse(status)) => {
                    return status;
                },
                msg => self.buffer.push(msg)
            }
        }
    }
}

/// A server/node/peer is the most atomic unit within a cluster. Each node is equal with it's peers,
/// thus we don't have any leader or election processes. Each server is identified with a unique ID
/// that is randomly generated, along with the appropriate state.
///
/// A server requires a bit of metadata about the cluster, the cluster's state and things like
/// channels. Each server has it's own Receiver to handle incoming messages. A separate Receiver
/// is used for users of this library. We then have a Sender that sends to the server's receiver.
/// This is meant to be copied to the appropriate task.
///
/// Usage:
///
/// ```rust
/// use gossip::{InternalServer, Shutdown};
/// use std::time::duration::Duration;
///
/// let mut server = InternalServer::create("127.0.0.1", 5666);
///
/// // Shutdown in the specified time in seconds.
/// server.shutdown_in(Duration::seconds(1));
///
/// // Wait for new messages. This will block the main task until the
/// // server has been shutdown.
/// loop {
///     match server.recv() {
///         Shutdown(reason) => break,
///         _ => {}
///     }
/// }
/// ```
pub struct InternalServer {
    /// A unique id for the server. This allows servers to talk about each other in
    /// a consistent manner.
    id: Uuid,
    /// The server may have an address to bind to. We make it optional to have a cleaner API
    /// to initially create the server, as the address is only needed at the .listen method.
    addr: Option<Addr>,
    /// Keep track of the server's status so that operations can be applied or rejected depending
    /// on which status it's current set on. This allows us to track whether the server
    /// has already initiated a shutdown or whether it's still running.
    status: Status,
    /// The state handles the core Gossip protocol. It's basically a giant state machine
    /// that keeps track of which nodes to communicate with, which nodes are alive/dead/failing,
    /// etc...
    state: State,
    /// A collection of servers within the cluster. Note that these aren't allocated/running
    /// servers, so we use another record called `Node` to handle that understanding.
    servers: Vec<Node>,
    /// The internal receiver to handle incoming messages. These can be messages coming from a
    /// transport, or from a user.
    receiver: Receiver<ServerMessage>,
    /// The sender-half of the previous channel. This is copied to the user and transports to send
    /// incoming messages. These aren't always broadcasts! Broadcasts are simply one kind of server
    /// message.
    sender: Sender<ServerMessage>,
    /// This is the user sender so that we can communicate with the end user of this crate. Any
    /// broadcasts that we don't handle will be relayed to the user's sender and they can take
    /// care of it.
    tx: Sender<ServerMessage>
}

impl InternalServer {

    /// Create a standard, default server. This only initializes the server
    /// but does **not** start it! So it doesn't spawn a new thread.
    ///
    /// This function requires a Sender so that the server can relay messages
    /// externally (such as the user of the crate).
    pub fn new(sender: Sender<ServerMessage>) -> InternalServer {
        // Create an internal channel for the server. The sender is often
        // copied around to various components.
        let (tx, rx) = channel();

        InternalServer {
            id: Uuid::new_v4(),
            addr: None,
            status: Initializing,
            state: State::new(),
            servers: Vec::new(),
            receiver: rx,
            sender: tx,
            tx: sender
        }
    }

    /// Create a new `Server` that is responsible for fully initializing and starting
    /// the server component. A `Server` is what the user will interact with as the server
    /// is running within another task, so the communication protocol is through channels
    /// exclusively.
    pub fn create(ip: &str, port: u16) -> Server {
        Server::create(ip, port)
    }

    /// Bind the server to the specified address. If there's a transport,
    /// it has the possibility of failing.
    pub fn listen(&mut self, ip: &str, port: u16) -> GossipResult<()> {
        self.addr = Some(Addr::new(ip, port));
        self.status = Running;

        // FIXME: We'll probably need a select! macro invocation to allow the ability
        // to read from multiple sources.
        loop {
            // Receive the next message from the channel. This can be from any component.
            match self.receiver.recv() {
                // Ok, so we are tasked with shutting down. We'll relay the shutdown
                // message back to the user so they can do some cleanup or other operations.
                //
                // FIXME: We'll need to broadcast to the cluster that this server is shutting down.
                Shutdown(reason) => {
                    self.tx.send(Shutdown(reason));
                    break;
                },
                Query(StatusQuery) => {
                    self.tx.send(QueryResponse(StatusQueryResponse(self.status)));
                }
                _ => {}
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::{Arc, Mutex};

    #[test]
    fn should_have_default_server() {
        let (tx, rx) = channel();
        let s = InternalServer::new(tx);
        assert!(s.addr.is_none())
        assert_eq!(s.status, Initializing);
    }

    #[test]
    fn should_query_server_status() {
        let mut server = Server::create("localhost", 8777);
        assert_eq!(server.get_status(), Running);
        server.shutdown();

        server.recv();
    }

    #[test]
    fn should_not_send_without_peers() {
        let mut i = 0i;
        let mut server = Server::create("localhost", 8777);

        server.shutdown();

        loop {
            match server.recv() {
                Shutdown(reason) => {
                    if i != 0 {
                        fail!("Unexpected behaviour 1");
                    }
                    break;
                },
                Message(broadcast) => {
                    i += 1;
                },
                Failure(reason) if reason == BroadcastFailed => {
                    assert!(true);
                },
                _ => fail!("Unexpected behaviour 2")
            }
        }
    }

    #[test]
    fn should_have_mutex_with_server() {
        let (tx, rx) = channel();

        // Create the task local mutex.
        let mutex = Arc::new(Mutex::new(InternalServer::new(tx)));

        // Copy the mutex (through the Arc) for use in another task.
        let mutex2 = mutex.clone();

        // We need to get the sender from the server.
        let mut val = mutex.lock();
        let sender = (*val).sender.clone();

        // Release the mutex.
        drop(val);

        spawn(proc() {
            let mut val = mutex2.lock();
            val.listen("127.0.0.1", 8777);
        });

        // Shutdown the server so we can finish the test.
        sender.send(Shutdown(UserInitiatedShutdown));

        match rx.recv() {
            Shutdown(reason) if reason == UserInitiatedShutdown => {
                assert!(true);
            },
            _ => fail!("Unexpected output")
        }
    }

    #[test]
    fn should_shutdown_server() {
        let (tx, rx) = channel();
        let mut s = InternalServer::new(tx);

        s.sender.send(Shutdown(UserInitiatedShutdown));
    }
}
<|endoftext|>


<commit_before>mod arena;
mod messages;
mod primitives;

use actix::{Actor, AsyncContext, Context, Handler};
use anyhow::{anyhow, Context as ResultContext, Error};
use log::{error, info, warn};
use std::collections::HashMap;
use std::time::Duration;

pub use arena::{Arena, ArenaInput, ArenaOverview, ArenaUpdate};
pub use messages::{MessageIn, MessageOut};
pub use primitives::*;

use crate::get_error_chain;
use messages::MessageInPayload;

const UPDATE_RATE_MILLISECONDS: u64 = 25; // 1000 / 25 = 40 updates per second

#[derive(Debug, Default)]
pub struct Server {
    message_queue: Vec<MessageIn>,
    clients: HashMap<ClientId, Client>,
    arenas: HashMap<ArenaId, Arena>,
}

impl Server {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn new_arena(&mut self) -> ArenaId {
        let arena = Arena::default();
        let id = arena.id;

        self.arenas.insert(id, arena);

        id
    }

    pub fn client_input(&mut self, client_id: ClientId, input: ArenaInput) -> Result<(), Error> {
        let client = self
            .clients
            .get(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.process_input(player_id, input);

        Ok(())
    }

    pub fn client_part_arena(&mut self, client_id: ClientId) -> Result<(), Error> {
        let client = self
            .clients
            .get_mut(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        client.updates_sent_so_far = 0;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.remove_player(player_id);

        // TODO: Remove empty arenas

        Ok(())
    }
}

impl Server {
    pub fn handle_message(
        &mut self,
        client_id: ClientId,
        payload: MessageInPayload,
    ) -> Result<(), Error> {
        match payload {
            MessageInPayload::Connect(ip_address, address) => {
                info!("Client connected: {}", client_id);
                self.clients.insert(
                    client_id,
                    Client {
                        id: client_id,
                        ip_address,
                        address,
                        player: None,
                        arena: None,
                        updates_sent_so_far: 0,
                    },
                );
            }
            MessageInPayload::Disconnect => {
                info!("Client disconnected: {}", client_id);

                self.client_part_arena(client_id).unwrap_or_else(|error| {
                    warn!("Failed to remove client from their arena: {}", error)
                });

                self.clients
                    .remove(&client_id)
                    .ok_or_else(|| anyhow!("Failed to remove client {}", client_id))?;
            }

            MessageInPayload::GetArenaList => {
                let arena_list: Vec<ArenaOverview> =
                    self.arenas.values().map(ArenaOverview::from).collect();

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                client
                    .address
                    .try_send(MessageOut::ArenaList(arena_list))
                    .with_context(|| anyhow!("Failed to send ArenaList to client {}", client_id))?;
            }
            MessageInPayload::Join { player, arena_id } => {
                self.client_part_arena(client_id).unwrap_or_else(|error| {
                    warn!("Failed to remove client from their arena: {}", error)
                });

                let arena_id = match arena_id {
                    Some(arena_id) => {
                        if self.arenas.contains_key(&arena_id) {
                            arena_id
                        } else {
                            self.new_arena()
                        }
                    }
                    None => self.new_arena(),
                };

                let arena = self
                    .arenas
                    .get_mut(&arena_id)
                    .ok_or_else(|| anyhow!("Arena {} not found", arena_id))?;

                if arena.players.len() >= arena.max_players {
                    return Err(anyhow!("Arena {} is full", arena_id));
                }

                let player_id = player.id;

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                arena.add_player(player);
                client.player = Some(player_id);
                client.arena = Some(arena_id);

                client
                    .address
                    .try_send(MessageOut::ArenaJoined(arena.id))
                    .with_context(|| {
                        anyhow!("Failed to send ArenaJoined to client {}", client_id)
                    })?;

                info!("Player {} joined arena {}", player_id, arena_id);
            }

            MessageInPayload::Start => {
                self.client_input(client_id, ArenaInput::Start)?;
            }
            MessageInPayload::Turn(direction) => {
                self.client_input(client_id, ArenaInput::Turn(direction))?;
            }
        }
        Ok(())
    }
}

impl Server {
    pub fn process_messages(&mut self) {
        // take ownership of queued messages
        let mut process_messages_queue = Vec::with_capacity(self.message_queue.len());

        // move all message_queue messages into process_messages_queue
        process_messages_queue.append(&mut self.message_queue);

        // process each message
        process_messages_queue.drain(..).for_each(|message| {
            self.handle_message(message.client_id, message.payload)
                .unwrap_or_else(|error| {
                    error!("Failed processing MessageIn: {}", get_error_chain(error))
                });
        });
    }

    pub fn update(&mut self) {
        self.arenas.values_mut().for_each(|arena| arena.update());
    }

    pub fn send_updates(&mut self) {
        let clients = &mut self.clients;
        let arenas = &self.arenas;

        clients.values_mut().for_each(|client| {
            let arena = match client.arena {
                Some(arena) => arena,
                None => return,
            };

            let arena = match arenas.get(&arena) {
                Some(arena) => arena,
                None => return,
            };

            if client.updates_sent_so_far == 0 {
                unwrap_or_return!(
                    client
                        .address
                        .try_send(MessageOut::ArenaState(Box::from(arena.clone()))),
                    |error| error!("Failed to send ArenaState to client: {}", error)
                );
                client.updates_sent_so_far = arena.updates.len();
                return;
            }

            if client.updates_sent_so_far < arena.updates.len() {
                client
                    .address
                    .try_send(MessageOut::ArenaStatePatch(
                        arena
                            .updates
                            .iter()
                            .skip(client.updates_sent_so_far)
                            .cloned()
                            .collect(),
                    ))
                    .unwrap_or_else(|error| {
                        error!("Failed to send ArenaStatePatch to client: {}", error);
                    });
                client.updates_sent_so_far = arena.updates.len();
                return;
            }
        })
    }
}

impl Actor for Server {
    type Context = Context<Self>;

    fn started(&mut self, context: &mut Context<Self>) {
        context.run_interval(
            Duration::from_millis(UPDATE_RATE_MILLISECONDS),
            |server, _context| {
                server.process_messages();
                server.update();
                server.send_updates();
            },
        );
    }
}

impl Handler<MessageIn> for Server {
    type Result = ();

    fn handle(&mut self, message: MessageIn, _context: &mut Context<Self>) {
        self.message_queue.push(message);
    }
}
<commit_msg>added server check to remove empty arenas<commit_after>mod arena;
mod messages;
mod primitives;

use actix::{Actor, AsyncContext, Context, Handler};
use anyhow::{anyhow, Context as ResultContext, Error};
use log::{error, info, warn};
use std::collections::HashMap;
use std::time::Duration;

pub use arena::{Arena, ArenaInput, ArenaOverview, ArenaUpdate};
pub use messages::{MessageIn, MessageOut};
pub use primitives::*;

use crate::get_error_chain;
use messages::MessageInPayload;

const UPDATE_RATE_MILLISECONDS: u64 = 25; // 1000 / 25 = 40 updates per second

#[derive(Debug, Default)]
pub struct Server {
    message_queue: Vec<MessageIn>,
    clients: HashMap<ClientId, Client>,
    arenas: HashMap<ArenaId, Arena>,
}

impl Server {
    pub fn new() -> Self {
        Default::default()
    }

    pub fn new_arena(&mut self) -> ArenaId {
        let arena = Arena::default();
        let id = arena.id;

        self.arenas.insert(id, arena);

        id
    }

    pub fn client_input(&mut self, client_id: ClientId, input: ArenaInput) -> Result<(), Error> {
        let client = self
            .clients
            .get(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.process_input(player_id, input);

        Ok(())
    }

    pub fn client_part_arena(&mut self, client_id: ClientId) -> Result<(), Error> {
        let client = self
            .clients
            .get_mut(&client_id)
            .with_context(|| anyhow!("Client {} not found", client_id))?;

        client.updates_sent_so_far = 0;

        let arena_id = client
            .arena
            .with_context(|| anyhow!("Client {} not in an arena"))?;

        let arena = self
            .arenas
            .get_mut(&arena_id)
            .with_context(|| anyhow!("Arena {} not found", arena_id))?;

        let player_id = client
            .player
            .with_context(|| anyhow!("Client {} has no player", client_id))?;

        arena.remove_player(player_id);

        Ok(())
    }
}

impl Server {
    pub fn handle_message(
        &mut self,
        client_id: ClientId,
        payload: MessageInPayload,
    ) -> Result<(), Error> {
        match payload {
            MessageInPayload::Connect(ip_address, address) => {
                info!("Client connected: {}", client_id);
                self.clients.insert(
                    client_id,
                    Client {
                        id: client_id,
                        ip_address,
                        address,
                        player: None,
                        arena: None,
                        updates_sent_so_far: 0,
                    },
                );
            }
            MessageInPayload::Disconnect => {
                info!("Client disconnected: {}", client_id);

                self.client_part_arena(client_id).unwrap_or_else(|error| {
                    warn!("Failed to remove client from their arena: {}", error)
                });

                self.clients
                    .remove(&client_id)
                    .ok_or_else(|| anyhow!("Failed to remove client {}", client_id))?;
            }

            MessageInPayload::GetArenaList => {
                let arena_list: Vec<ArenaOverview> =
                    self.arenas.values().map(ArenaOverview::from).collect();

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                client
                    .address
                    .try_send(MessageOut::ArenaList(arena_list))
                    .with_context(|| anyhow!("Failed to send ArenaList to client {}", client_id))?;
            }
            MessageInPayload::Join { player, arena_id } => {
                self.client_part_arena(client_id).unwrap_or_else(|error| {
                    warn!("Failed to remove client from their arena: {}", error)
                });

                let arena_id = match arena_id {
                    Some(arena_id) => {
                        if self.arenas.contains_key(&arena_id) {
                            arena_id
                        } else {
                            self.new_arena()
                        }
                    }
                    None => self.new_arena(),
                };

                let arena = self
                    .arenas
                    .get_mut(&arena_id)
                    .ok_or_else(|| anyhow!("Arena {} not found", arena_id))?;

                if arena.players.len() >= arena.max_players {
                    return Err(anyhow!("Arena {} is full", arena_id));
                }

                let player_id = player.id;

                let client = self
                    .clients
                    .get_mut(&client_id)
                    .ok_or_else(|| anyhow!("Client {} not found", client_id))?;

                arena.add_player(player);
                client.player = Some(player_id);
                client.arena = Some(arena_id);

                client
                    .address
                    .try_send(MessageOut::ArenaJoined(arena.id))
                    .with_context(|| {
                        anyhow!("Failed to send ArenaJoined to client {}", client_id)
                    })?;

                info!("Player {} joined arena {}", player_id, arena_id);
            }

            MessageInPayload::Start => {
                self.client_input(client_id, ArenaInput::Start)?;
            }
            MessageInPayload::Turn(direction) => {
                self.client_input(client_id, ArenaInput::Turn(direction))?;
            }
        }
        Ok(())
    }
}

impl Server {
    pub fn process_messages(&mut self) {
        // take ownership of queued messages
        let mut process_messages_queue = Vec::with_capacity(self.message_queue.len());

        // move all message_queue messages into process_messages_queue
        process_messages_queue.append(&mut self.message_queue);

        // process each message
        process_messages_queue.drain(..).for_each(|message| {
            self.handle_message(message.client_id, message.payload)
                .unwrap_or_else(|error| {
                    error!("Failed processing MessageIn: {}", get_error_chain(error))
                });
        });
    }

    pub fn update(&mut self) {
        self.arenas.retain(|_, arena| {
            arena.update();

            // discard arena if all players have left
            arena.players.len() > 0
        })
    }

    pub fn send_updates(&mut self) {
        let clients = &mut self.clients;
        let arenas = &self.arenas;

        clients.values_mut().for_each(|client| {
            let arena = match client.arena {
                Some(arena) => arena,
                None => return,
            };

            let arena = match arenas.get(&arena) {
                Some(arena) => arena,
                None => return,
            };

            if client.updates_sent_so_far == 0 {
                unwrap_or_return!(
                    client
                        .address
                        .try_send(MessageOut::ArenaState(Box::from(arena.clone()))),
                    |error| error!("Failed to send ArenaState to client: {}", error)
                );
                client.updates_sent_so_far = arena.updates.len();
                return;
            }

            if client.updates_sent_so_far < arena.updates.len() {
                client
                    .address
                    .try_send(MessageOut::ArenaStatePatch(
                        arena
                            .updates
                            .iter()
                            .skip(client.updates_sent_so_far)
                            .cloned()
                            .collect(),
                    ))
                    .unwrap_or_else(|error| {
                        error!("Failed to send ArenaStatePatch to client: {}", error);
                    });
                client.updates_sent_so_far = arena.updates.len();
                return;
            }
        })
    }
}

impl Actor for Server {
    type Context = Context<Self>;

    fn started(&mut self, context: &mut Context<Self>) {
        context.run_interval(
            Duration::from_millis(UPDATE_RATE_MILLISECONDS),
            |server, _context| {
                server.process_messages();
                server.update();
                server.send_updates();
            },
        );
    }
}

impl Handler<MessageIn> for Server {
    type Result = ();

    fn handle(&mut self, message: MessageIn, _context: &mut Context<Self>) {
        self.message_queue.push(message);
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::collections::HashMap;
use std::net::ToSocketAddrs;

use mime_guess::guess_mime_type;

use hyper::Server;
use hyper::server::{Handler, Listening, Request, Response};
use hyper::uri::RequestUri;
use hyper::header::ContentType;
use hyper::status::StatusCode;

pub type StaticMap = HashMap<String, Vec<u8>>;

pub trait StaicProvider {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>>;
}

impl StaicProvider for StaticMap {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>> {
		self.get(path)
	}
}

pub struct StaticWorker {
	listening: Listening,
}

impl Drop for StaticWorker {
	fn drop(&mut self) {
		let _ = self.listening.close();
	}
}

// TODO Add trait StaticMapCreater with fn(path) and update/read method
pub struct StaticServer {
	map: Arc<StaticMap>,
}

impl StaticServer {

	pub fn new(map: StaticMap) -> Self {
		StaticServer { map: Arc::new(map) }
	}

	pub fn share<To: ToSocketAddrs>(&self, addr: To) -> Result<StaticWorker, ()> {
		let server = match Server::http(addr) {
			Ok(server) => server,
			Err(_) => return Err(()),
		};
		let map = self.map.clone();
		let handler = move |req: Request, mut res: Response| {
	    	match req.uri {
	    		RequestUri::AbsolutePath(mut spath) => {
	    			if spath.ends_with("/") {
	    				spath.push_str("index.html")
	    			}
	    			let mime = guess_mime_type(spath.as_ref());
					res.headers_mut().set(ContentType(mime));
					match map.get_content(&spath) {
						Some(item) => {
							*res.status_mut() = StatusCode::Ok;
							&res.send(item).unwrap();
						},
						None => *res.status_mut() = StatusCode::NotFound,
					}
				},
				_ => *res.status_mut() = StatusCode::BadRequest,
			};
		};
		match server.handle(handler) {
			Ok(listening) => {
				let worker = StaticWorker{ listening: listening};
				Ok(worker)
			},
			Err(_) => return Err(()),
		}
	}
}
<commit_msg>Generic StaticServer provider<commit_after>use std::sync::Arc;
use std::collections::HashMap;
use std::net::ToSocketAddrs;

use mime_guess::guess_mime_type;

use hyper::Server;
use hyper::server::{Handler, Listening, Request, Response};
use hyper::uri::RequestUri;
use hyper::header::ContentType;
use hyper::status::StatusCode;

pub type StaticMap = HashMap<String, Vec<u8>>;

pub trait StaicProvider: Sync + Send + 'static {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>>;
}

impl StaicProvider for StaticMap {
	fn get_content(&self, path: &str) -> Option<&Vec<u8>> {
		self.get(path)
	}
}

pub struct StaticWorker {
	listening: Listening,
}

impl Drop for StaticWorker {
	fn drop(&mut self) {
		let _ = self.listening.close();
	}
}

// TODO Add trait StaticMapCreater with fn(path) and update/read method
pub struct StaticServer {
	map: Arc<StaicProvider>,
}

impl StaticServer {

	pub fn new<T: StaicProvider>(map: T) -> Self {
		StaticServer { map: Arc::new(map) }
	}

	pub fn share<To: ToSocketAddrs>(&self, addr: To) -> Result<StaticWorker, ()> {
		let server = match Server::http(addr) {
			Ok(server) => server,
			Err(_) => return Err(()),
		};
		let map = self.map.clone();
		let handler = move |req: Request, mut res: Response| {
	    	match req.uri {
	    		RequestUri::AbsolutePath(mut spath) => {
	    			if spath.ends_with("/") {
	    				spath.push_str("index.html")
	    			}
	    			let mime = guess_mime_type(spath.as_ref());
					res.headers_mut().set(ContentType(mime));
					match map.get_content(&spath) {
						Some(item) => {
							*res.status_mut() = StatusCode::Ok;
							&res.send(item).unwrap();
						},
						None => *res.status_mut() = StatusCode::NotFound,
					}
				},
				_ => *res.status_mut() = StatusCode::BadRequest,
			};
		};
		match server.handle(handler) {
			Ok(listening) => {
				let worker = StaticWorker{ listening: listening};
				Ok(worker)
			},
			Err(_) => return Err(()),
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;

pub use glib::signal::Inhibit;
use glib::SourceId;
use glib::translate::*;
use glib::signal::SignalHandlerId;
use gdk::Rectangle;

use glib_ffi::{self, gboolean, gpointer};

use {
    Continue,
    ScrollType,
    Widget,
};

// idle_add and timeout_add fixed to the main thread

unsafe extern "C" fn trampoline<F: FnMut() -> Continue + 'static>(func: gpointer) -> gboolean {
    let func: &RefCell<F> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure<F: FnMut() -> Continue + 'static>(ptr: gpointer) {
    Box::<RefCell<F>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<F>> = Box::new(RefCell::new(func));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// Similar to `glib::idle_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn idle_add<F>(func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline::<F>),
            into_raw(func), Some(destroy_closure::<F>)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// Similar to `glib::timeout_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(
            glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline::<F>),
                 into_raw(func), Some(destroy_closure::<F>)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// Similar to `glib::timeout_add_seconds` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline::<F>), into_raw(func), Some(destroy_closure::<F>)))
    }
}

pub trait EditableSignals: 'static {
    fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
    fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static;
    fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static;
}

mod editable {
    use Editable;
    use std::mem::transmute;
    use ffi::GtkEditable;
    use glib::signal::{SignalHandlerId, connect_raw};
    use glib::translate::*;
    use IsA;
    use libc::{c_char, c_int, c_uchar};
    use std::ffi::CStr;
    use std::str;
    use glib::object::Cast;
    use std::slice;

    impl<T: IsA<Editable>> super::EditableSignals for T {
        fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<F> = Box::new(changed_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"changed\0".as_ptr() as *mut _,
                    Some(transmute(trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static {
            unsafe {
                let f: Box<F> = Box::new(delete_text_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"delete-text\0".as_ptr() as *mut _,
                    Some(transmute(delete_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static {
            unsafe {
                let f: Box<F> = Box::new(insert_text_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"insert-text\0".as_ptr() as *mut _,
                    Some(transmute(insert_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }
    }

    unsafe extern "C" fn trampoline<T, F: Fn(&T) + 'static>(this: *mut GtkEditable,
                                                            f: &F)
    where T: IsA<Editable> {
        f(&Editable::from_glib_borrow(this).unsafe_cast());
    }

    unsafe extern "C" fn delete_trampoline<T, F: Fn(&T, i32, i32) + 'static>(this: *mut GtkEditable,
                                                                             start_pos: c_int,
                                                                             end_pos: c_int,
                                                                             f: &F)
    where T: IsA<Editable> {
        f(&Editable::from_glib_borrow(this).unsafe_cast(), start_pos, end_pos);
    }

    unsafe extern "C" fn insert_trampoline<T, F: Fn(&T, &str, &mut i32) + 'static>(this: *mut GtkEditable,
                                                                                new_text: *mut c_char,
                                                                                new_text_length: c_int,
                                                                                position: *mut c_int,
                                                                                f: &F)
    where T: IsA<Editable> {
        let buf = if new_text_length != -1 {
            slice::from_raw_parts(new_text as *mut c_uchar,
                                  new_text_length as usize)
        } else {
            CStr::from_ptr(new_text).to_bytes()
        };
        let string = str::from_utf8(buf).unwrap();
        f(&Editable::from_glib_borrow(this).unsafe_cast(),
          string,
          transmute(position));
    }
}

pub trait SpinButtonSignals: 'static {
    fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&Self, ScrollType) + 'static;
    fn connect_input<F>(&self, input_func: F) -> SignalHandlerId
        where F: Fn(&Self) -> Option<Result<f64, ()>> + 'static;
    fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&Self) -> Inhibit + 'static;
    fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
    fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
}

mod spin_button {
    use Inhibit;
    use SpinButton;
    use ScrollType;
    use ffi::{GTK_INPUT_ERROR, GtkSpinButton};
    use glib::signal::{SignalHandlerId, connect_raw};
    use glib::object::Cast;
    use glib::IsA;
    use glib::translate::*;
    use glib_ffi::{GTRUE, GFALSE};
    use libc::{c_int, c_double};
    use std::boxed::Box as Box_;
    use std::mem::transmute;
    use glib_ffi::gboolean;

    impl<T: IsA<SpinButton>> ::SpinButtonSignals for T {
        fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&Self, ScrollType) + 'static {
            unsafe {
                let f: Box<F> = Box::new(change_value_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"change_value\0".as_ptr() as *mut _,
                        Some(transmute(change_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_input<F>(&self, f: F) -> SignalHandlerId
        where F: Fn(&Self) -> Option<Result<f64, ()>> + 'static {
            unsafe {
                let f: Box_<F> = Box_::new(f);
                connect_raw(self.to_glib_none().0 as *mut _, b"input\0".as_ptr() as *mut _,
                        Some(transmute(input_trampoline::<Self, F> as usize)), Box_::into_raw(f))
            }
        }

        fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&Self) -> Inhibit + 'static {
            unsafe {
                let f: Box<F> = Box::new(output_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"output\0".as_ptr() as *mut _,
                        Some(transmute(output_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<F> = Box::new(value_changed_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"value-changed\0".as_ptr() as *mut _,
                        Some(transmute(trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<F> = Box::new(wrapped_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"wrapped\0".as_ptr() as *mut _,
                        Some(transmute(trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }
    }

    unsafe extern "C" fn change_trampoline<T, F: Fn(&T, ScrollType) + 'static>(this: *mut GtkSpinButton,
                                           scroll: ScrollType,
                                           f: &F)
    where T: IsA<SpinButton> {
        f(&SpinButton::from_glib_borrow(this).unsafe_cast(), scroll)
    }

    unsafe extern "C" fn input_trampoline<T, F: Fn(&T) -> Option<Result<f64, ()>> + 'static>(this: *mut GtkSpinButton,
                                          new_value: *mut c_double,
                                          f: &F)
                                          -> c_int
    where T: IsA<SpinButton> {
        match f(&SpinButton::from_glib_borrow(this).unsafe_cast()) {
            Some(Ok(v)) => {
                *new_value = v;
                GTRUE
            }
            Some(Err(_)) => GTK_INPUT_ERROR,
            None => GFALSE,
        }
    }

    unsafe extern "C" fn output_trampoline<T, F: Fn(&T) -> Inhibit + 'static>(this: *mut GtkSpinButton,
                                                                              f: &F) -> gboolean
    where T: IsA<SpinButton> {
        f(&SpinButton::from_glib_borrow(this).unsafe_cast()).to_glib()
    }

    unsafe extern "C" fn trampoline<T, F:  Fn(&T) + 'static>(this: *mut GtkSpinButton,
                                                             f: &F)
    where T: IsA<SpinButton> {
        f(&SpinButton::from_glib_borrow(this).unsafe_cast())
    }
}

pub trait OverlaySignals: 'static {
    fn connect_get_child_position<F>(&self, f: F) -> SignalHandlerId
    where
        F: Fn(&Self, &Widget) -> Option<Rectangle> + 'static;
}

mod overlay {
    use gdk::Rectangle;
    use ffi::{GtkOverlay, GtkWidget};
    use gdk_ffi::GdkRectangle;
    use glib::signal::{connect_raw, SignalHandlerId};
    use glib::translate::*;
    use glib::object::Cast;
    use std::mem::transmute;
    use std::ptr;
    use glib_ffi::{gboolean, gpointer};
    use IsA;
    use Overlay;
    use Widget;

    impl<O: IsA<Overlay>> ::OverlaySignals for O {
        fn connect_get_child_position<F>(&self, f: F) -> SignalHandlerId
        where
            F: Fn(&Self, &Widget) -> Option<Rectangle> + 'static,
        {
            unsafe {
                let f: Box<F> = Box::new(f);
                connect_raw(
                    self.to_glib_none().0 as *mut _,
                    b"get-child-position\0".as_ptr() as *mut _,
                    Some(transmute(get_child_position_trampoline::<Self, F> as usize)),
                    Box::into_raw(f),
                )
            }
        }
    }

    unsafe extern "C" fn get_child_position_trampoline<T, F: Fn(&T, &Widget) -> Option<Rectangle> + 'static>(
        this: *mut GtkOverlay,
        widget: *mut GtkWidget,
        allocation: *mut GdkRectangle,
        f: gpointer,
    ) -> gboolean
    where
        T: IsA<Overlay>,
    {
        let f: &F = transmute(f);
        match f(
            &Overlay::from_glib_borrow(this).unsafe_cast(),
            &from_glib_borrow(widget),
        ) {
            Some(rect) => {
                ptr::write(allocation, ptr::read(rect.to_glib_none().0));
                true
            }
            None => false,
        }.to_glib()
    }
}
<commit_msg>Make gtk::idle_add() and others simple wrappers around the ones from glib<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib;
pub use glib::signal::Inhibit;
use glib::SourceId;
use glib::signal::SignalHandlerId;
use gdk::Rectangle;

use {
    Continue,
    ScrollType,
    Widget,
};

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// Similar to `glib::idle_add` but only callable from the main thread and
/// doesn't require `Send`. It is the same as `glib::idle_add_local`.
pub fn idle_add<F>(func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    glib::idle_add_local(func)
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// Similar to `glib::timeout_add` but only callable from the main thread and
/// doesn't require `Send`. It is the same as `glib::timeout_add_local`.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    glib::timeout_add_local(interval, func)
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// Similar to `glib::timeout_add_seconds` but only callable from the main thread and
/// doesn't require `Send`. It is the same as `glib::timeout_add_seconds_local`.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    glib::timeout_add_seconds_local(interval, func)
}

pub trait EditableSignals: 'static {
    fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
    fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static;
    fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static;
}

mod editable {
    use Editable;
    use std::mem::transmute;
    use ffi::GtkEditable;
    use glib::signal::{SignalHandlerId, connect_raw};
    use glib::translate::*;
    use IsA;
    use libc::{c_char, c_int, c_uchar};
    use std::ffi::CStr;
    use std::str;
    use glib::object::Cast;
    use std::slice;

    impl<T: IsA<Editable>> super::EditableSignals for T {
        fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<F> = Box::new(changed_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"changed\0".as_ptr() as *mut _,
                    Some(transmute(trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static {
            unsafe {
                let f: Box<F> = Box::new(delete_text_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"delete-text\0".as_ptr() as *mut _,
                    Some(transmute(delete_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static {
            unsafe {
                let f: Box<F> = Box::new(insert_text_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"insert-text\0".as_ptr() as *mut _,
                    Some(transmute(insert_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }
    }

    unsafe extern "C" fn trampoline<T, F: Fn(&T) + 'static>(this: *mut GtkEditable,
                                                            f: &F)
    where T: IsA<Editable> {
        f(&Editable::from_glib_borrow(this).unsafe_cast());
    }

    unsafe extern "C" fn delete_trampoline<T, F: Fn(&T, i32, i32) + 'static>(this: *mut GtkEditable,
                                                                             start_pos: c_int,
                                                                             end_pos: c_int,
                                                                             f: &F)
    where T: IsA<Editable> {
        f(&Editable::from_glib_borrow(this).unsafe_cast(), start_pos, end_pos);
    }

    unsafe extern "C" fn insert_trampoline<T, F: Fn(&T, &str, &mut i32) + 'static>(this: *mut GtkEditable,
                                                                                new_text: *mut c_char,
                                                                                new_text_length: c_int,
                                                                                position: *mut c_int,
                                                                                f: &F)
    where T: IsA<Editable> {
        let buf = if new_text_length != -1 {
            slice::from_raw_parts(new_text as *mut c_uchar,
                                  new_text_length as usize)
        } else {
            CStr::from_ptr(new_text).to_bytes()
        };
        let string = str::from_utf8(buf).unwrap();
        f(&Editable::from_glib_borrow(this).unsafe_cast(),
          string,
          transmute(position));
    }
}

pub trait SpinButtonSignals: 'static {
    fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&Self, ScrollType) + 'static;
    fn connect_input<F>(&self, input_func: F) -> SignalHandlerId
        where F: Fn(&Self) -> Option<Result<f64, ()>> + 'static;
    fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&Self) -> Inhibit + 'static;
    fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
    fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
}

mod spin_button {
    use Inhibit;
    use SpinButton;
    use ScrollType;
    use ffi::{GTK_INPUT_ERROR, GtkSpinButton};
    use glib::signal::{SignalHandlerId, connect_raw};
    use glib::object::Cast;
    use glib::IsA;
    use glib::translate::*;
    use glib_ffi::{GTRUE, GFALSE};
    use libc::{c_int, c_double};
    use std::boxed::Box as Box_;
    use std::mem::transmute;
    use glib_ffi::gboolean;

    impl<T: IsA<SpinButton>> ::SpinButtonSignals for T {
        fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&Self, ScrollType) + 'static {
            unsafe {
                let f: Box<F> = Box::new(change_value_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"change_value\0".as_ptr() as *mut _,
                        Some(transmute(change_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_input<F>(&self, f: F) -> SignalHandlerId
        where F: Fn(&Self) -> Option<Result<f64, ()>> + 'static {
            unsafe {
                let f: Box_<F> = Box_::new(f);
                connect_raw(self.to_glib_none().0 as *mut _, b"input\0".as_ptr() as *mut _,
                        Some(transmute(input_trampoline::<Self, F> as usize)), Box_::into_raw(f))
            }
        }

        fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&Self) -> Inhibit + 'static {
            unsafe {
                let f: Box<F> = Box::new(output_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"output\0".as_ptr() as *mut _,
                        Some(transmute(output_trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<F> = Box::new(value_changed_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"value-changed\0".as_ptr() as *mut _,
                        Some(transmute(trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }

        fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<F> = Box::new(wrapped_func);
                connect_raw(self.to_glib_none().0 as *mut _, b"wrapped\0".as_ptr() as *mut _,
                        Some(transmute(trampoline::<Self, F> as usize)), Box::into_raw(f))
            }
        }
    }

    unsafe extern "C" fn change_trampoline<T, F: Fn(&T, ScrollType) + 'static>(this: *mut GtkSpinButton,
                                           scroll: ScrollType,
                                           f: &F)
    where T: IsA<SpinButton> {
        f(&SpinButton::from_glib_borrow(this).unsafe_cast(), scroll)
    }

    unsafe extern "C" fn input_trampoline<T, F: Fn(&T) -> Option<Result<f64, ()>> + 'static>(this: *mut GtkSpinButton,
                                          new_value: *mut c_double,
                                          f: &F)
                                          -> c_int
    where T: IsA<SpinButton> {
        match f(&SpinButton::from_glib_borrow(this).unsafe_cast()) {
            Some(Ok(v)) => {
                *new_value = v;
                GTRUE
            }
            Some(Err(_)) => GTK_INPUT_ERROR,
            None => GFALSE,
        }
    }

    unsafe extern "C" fn output_trampoline<T, F: Fn(&T) -> Inhibit + 'static>(this: *mut GtkSpinButton,
                                                                              f: &F) -> gboolean
    where T: IsA<SpinButton> {
        f(&SpinButton::from_glib_borrow(this).unsafe_cast()).to_glib()
    }

    unsafe extern "C" fn trampoline<T, F:  Fn(&T) + 'static>(this: *mut GtkSpinButton,
                                                             f: &F)
    where T: IsA<SpinButton> {
        f(&SpinButton::from_glib_borrow(this).unsafe_cast())
    }
}

pub trait OverlaySignals: 'static {
    fn connect_get_child_position<F>(&self, f: F) -> SignalHandlerId
    where
        F: Fn(&Self, &Widget) -> Option<Rectangle> + 'static;
}

mod overlay {
    use gdk::Rectangle;
    use ffi::{GtkOverlay, GtkWidget};
    use gdk_ffi::GdkRectangle;
    use glib::signal::{connect_raw, SignalHandlerId};
    use glib::translate::*;
    use glib::object::Cast;
    use std::mem::transmute;
    use std::ptr;
    use glib_ffi::{gboolean, gpointer};
    use IsA;
    use Overlay;
    use Widget;

    impl<O: IsA<Overlay>> ::OverlaySignals for O {
        fn connect_get_child_position<F>(&self, f: F) -> SignalHandlerId
        where
            F: Fn(&Self, &Widget) -> Option<Rectangle> + 'static,
        {
            unsafe {
                let f: Box<F> = Box::new(f);
                connect_raw(
                    self.to_glib_none().0 as *mut _,
                    b"get-child-position\0".as_ptr() as *mut _,
                    Some(transmute(get_child_position_trampoline::<Self, F> as usize)),
                    Box::into_raw(f),
                )
            }
        }
    }

    unsafe extern "C" fn get_child_position_trampoline<T, F: Fn(&T, &Widget) -> Option<Rectangle> + 'static>(
        this: *mut GtkOverlay,
        widget: *mut GtkWidget,
        allocation: *mut GdkRectangle,
        f: gpointer,
    ) -> gboolean
    where
        T: IsA<Overlay>,
    {
        let f: &F = transmute(f);
        match f(
            &Overlay::from_glib_borrow(this).unsafe_cast(),
            &from_glib_borrow(widget),
        ) {
            Some(rect) => {
                ptr::write(allocation, ptr::read(rect.to_glib_none().0));
                true
            }
            None => false,
        }.to_glib()
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::ops::DerefMut;
use std::mem::transmute;
use glib_ffi::{gboolean, gpointer, g_idle_add_full, g_timeout_add_full, g_timeout_add_seconds_full};
use translate::ToGlib;

pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

// Box::into_raw stability workaround
unsafe fn into_raw<T>(b: Box<T>) -> *mut T { transmute(b) }

extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean {
    func.borrow_mut().deref_mut()().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    // Box::from_raw API stability workaround
    let ptr = ptr as *mut RefCell<Box<FnMut() -> Continue + 'static>>;
    let _: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = transmute(ptr);
}

const PRIORITY_DEFAULT: i32 = 0;
const PRIORITY_DEFAULT_IDLE: i32 = 200;

pub fn idle_add<F>(func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_idle_add_full(PRIORITY_DEFAULT_IDLE, transmute(trampoline),
            into_raw(f) as gpointer, Some(destroy_closure))
    }
}

pub fn timeout_add<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_timeout_add_full(PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(f) as gpointer, Some(destroy_closure))
    }
}

pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + 'static {
    let f: Box<RefCell<Box<FnMut() -> Continue + 'static>>> = Box::new(RefCell::new(Box::new(func)));
    unsafe {
        g_timeout_add_seconds_full(PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(f) as gpointer, Some(destroy_closure))
    }
}
<commit_msg>Add `Send` bound and panic guard to `idle_add` and `timeout_add`<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;
use std::process;
use std::thread;
use glib_ffi::{self, gboolean, gpointer};
use translate::ToGlib;

pub struct Continue(pub bool);

impl ToGlib for Continue {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

struct CallbackGuard;

impl Drop for CallbackGuard {
    fn drop(&mut self) {
        if thread::panicking() {
            process::exit(101);
        }
    }
}

extern "C" fn trampoline(func: &RefCell<Box<FnMut() -> Continue + 'static>>) -> gboolean {
    let _guard = CallbackGuard;
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    let _guard = CallbackGuard;
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + Send + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + Send + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

pub fn idle_add<F>(func: F) -> u32
    where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, transmute(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

pub fn timeout_add<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, transmute(trampoline),
            into_raw(func), Some(destroy_closure))
    }
}

pub fn timeout_add_seconds<F>(interval: u32, func: F) -> u32
    where F: FnMut() -> Continue + Send + 'static {
    unsafe {
        glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            transmute(trampoline), into_raw(func), Some(destroy_closure))
    }
}
<|endoftext|>