Ejemplo n.º 1
0
 def __init__(self):
     self._config = configuration.Configuration()
     self._server = None
     self._incoming_connections = []
     self._outgoing_connections = []
     self._message_queues = {}
     self._players = {}
     self._board = Board()
     self._current_sign = Sign.circle
     self.game_started = False
Ejemplo n.º 2
0
 def restart_game(self):
     self._board = Board()
     self._current_sign = Sign.circle
     self.game_started = False
Ejemplo n.º 3
0
class Server:
    def __init__(self):
        self._config = configuration.Configuration()
        self._server = None
        self._incoming_connections = []
        self._outgoing_connections = []
        self._message_queues = {}
        self._players = {}
        self._board = Board()
        self._current_sign = Sign.circle
        self.game_started = False

    @property
    def board(self):
        return self._board

    @board.setter
    def board(self, value):
        self._board.board = value

    @property
    def server_port(self):
        return int(self._config.server_port)

    @property
    def server_host(self):
        return self._config.server_ip

    @property
    def server_address(self):
        return self.server_host, self.server_port

    def _initialize_socket(self):
        logger.debug('Starting server at {}:{}'.format(self.server_host, self.server_port))
        self._server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._server.setblocking(0)
        self._server.bind(self.server_address)
        self._server.listen(2)

    def stop(self):
        for i in self._incoming_connections:
            i.close()

    def start(self):
        self._initialize_socket()
        self._incoming_connections.append(self._server)
        while self._incoming_connections:
            logger.debug('Waiting for connections')
            readable, writable, exceptional = select.select(self._incoming_connections,
                                                            self._outgoing_connections,
                                                            self._incoming_connections,
                                                            )
            self._handle_incoming(readable)
            self._handle_outgoing(writable)
            self._handle_exceptional(exceptional)

    def _init_game(self):
        if len(self._players) < 2:
            return
        if not self.game_started:
            self.restart_game()
            self._send_all(msg.GameReady('All players connected - Game starting'))
            self.game_started = True
        if self.game_started:
            self._send_all(msg.GameStart('Current player: {}'.format(self._current_sign)))
            self._send_boards()

    def _handle_incoming(self, readable):
        for s in readable:
            wrapped_socket = SocketWrapper(s)
            if s is self._server:
                connection, client_address = s.accept()
                logger.debug('New connection from {}'.format(client_address))
                connection.setblocking(0)
                self._incoming_connections.append(connection)
                self._message_queues[connection] = queue.Queue()
            else:
                self._handle_message(wrapped_socket)

    def _handle_outgoing(self, writable):
        for s in writable:
            wrapped_socket = SocketWrapper(s)
            try:
                next_msg = self._message_queues[s].get_nowait()
            except queue.Empty:
                logger.debug('output queue for {} is empty'.format((s.getpeername())))
                self._outgoing_connections.remove(s)
            else:
                logger.debug('sending "%s" to %s' % (next_msg, s.getpeername()))
                wrapped_socket.send(next_msg)

    def _handle_exceptional(self, exceptional):
        for s in exceptional:
            logger.error('handling exceptional condition for', s.getpeername())
            self._incoming_connections.remove(s)
            if s in self._outgoing_connections:
                self._outgoing_connections.remove(s)
            s.close()
            del self._message_queues[s]

    def _handle_message(self, wrapped_sock):
        data = wrapped_sock.recv()
        sock = wrapped_sock.socket
        if data is None:
            logger.debug('Client {} - closed connection'.format(sock.getpeername()))
            if sock in self._outgoing_connections:
                self._outgoing_connections.remove(sock)
            if sock in self._players.keys():
                tmp = self._players[sock]
                self.restart_game()
                del self._players[sock]
                self._send_all('Player {} left the game, game restarts'.format(tmp))
            self._incoming_connections.remove(sock)
            sock.close()
            del self._message_queues[sock]
            return

        if isinstance(data, msg.JoinGame):
            logger.debug('Player joining from {}'.format(sock.getpeername()))
            if len(self._players) < 2:
                self._players[sock] = self._assign_sign()
                self._send(sock, msg.PlayerSign('You are: {}'.format(self._players[sock])))
                if len(self._players) >= 2:
                    self.game_started = True
                    self._init_game()
            else:
                logger.debug('Connection refused {} - Server is full'.format(sock.getpeername()))
                self._send(sock, msg.GameFull('Server is full'))
                self._incoming_connections.remove(sock)
        elif not self.game_started:
            self._send(sock, msg.GameNotReady('Game is not ready, waiting for more players'))
            return

        if isinstance(data, msg.RefreshBoard):
            logger.debug('Sending new board to {}'.format(sock.getpeername()))
            self._send(sock, msg.RefreshBoard(self.board))
        elif isinstance(data, msg.MakeMove):
            logger.debug('Player {} attempts to make move: {}'.format(sock.getpeername(), data))
            tmp = self._submit_move(data.message(), self._players[sock])
            self._send(sock, tmp)
            self.send_game_results()

    def is_finished(self):
        return self.board.is_finished

    def send_game_results(self):
        if self.is_finished():
            self._send_all(msg.GameFinish('Game has ended'))
            self.restart_game()

    def restart_game(self):
        self._board = Board()
        self._current_sign = Sign.circle
        self.game_started = False

    def _send_boards(self):
        self._send_all(msg.RefreshBoard(self.board))

    def _send_all(self, message):
        for s in self._players.keys():
            self._send(s, message)

    def _submit_move(self, xy, sign):
        try:
            if len(xy) < 2:
                raise IllegalMove('Illegal move - wrong arguments')
            if self._current_sign != sign:
                raise IllegalMove('Illegal move - wrong player')
            self._board.place(xy[0], xy[1], sign)
            self._next_round()
            self._send_boards()
            logger.debug('Accepted Move')
            return msg.MoveAccepted('Accepted')
        except IllegalMove as e:
            logger.debug('User provided illegal move')
            return msg.IllegalMove(str(e))

    def _next_round(self):
        self._current_sign = Sign.circle if self._current_sign == Sign.cross else Sign.cross

    def _send(self, sock, message):
        if sock not in self._outgoing_connections:
            self._outgoing_connections.append(sock)
        self._message_queues[sock].put(message)

    def _assign_sign(self):
        if len(self._players) == 0:
            return Sign.circle
        else:
            return Sign.cross