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
def restart_game(self): self._board = Board() self._current_sign = Sign.circle self.game_started = False
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