示例#1
0
    def read_loop(self, event):  # !TODO timeout to signal
        """ Thread that reads messages sent by the server. """

        while True:
            try:
                server_ans = recvTlv(self.sock)

                if TLV_OK_TAG in server_ans or TLV_FAIL_TAG in server_ans:  # ACK / NACK response - main thread is awaiting for it
                    # print("Message {} has ACK/NACK tag => saving to pipeline for future processing".format(server_ans))
                    self.pipeline.put(server_ans)
                    continue

                if TLV_NEWTURN_TAG in server_ans:
                    client_logger.debug(
                        "Put TLV_NEWTURN_TAG msg into the pipeline")
                    self.pipeline.put(server_ans)
                    continue

                # print("Message {} is a request from the server".format(server_ans))
                self.handle_answer(
                    server_ans)  # received msg is not a control msg
            except (OSError, EOFError) as e:
                print("\nServer error\n")
                client_logger.error("Error while reading data: " + str(e))
                os.kill(os.getpid(), signal.SIGINT
                        )  # should raise Keyboard interrupt in the main thread
                event.set()  # alarm main thread that program should exit
                return
            except Exception as e:
                client_logger.error("Other error while reading data: " +
                                    str(e))
                os.kill(os.getpid(), signal.SIGINT)
                event.set()  # alarm main thread that program should exit
                return
示例#2
0
    def send_roll_command(self):
        """Send roll dice command to the server and anticipate positive response with roll result"""
        while True:
            client_logger.debug("Sending roll command")
            tlv = add_tlv_tag(TLV_ROLLDICE_TAG, self.nickname)
            sendTlv(self.sock, tlv)

            if self.wait_for_ack(
            ) and TLV_ROLLDICERESULT_TAG in self.current_msg:
                client_logger.debug("ROLLDICE result: " +
                                    str(self.current_msg))
                print(
                    'Roll command successfully requested. Server returned {}'.
                    format(self.current_msg[TLV_ROLLDICERESULT_TAG]))
                if TLV_OPTION_SKIP in self.current_msg:
                    self.skip_turn = True
                    return
                self.player_options = option_parsing(self.current_msg)
                return
            else:
                if TLV_FAIL_TAG in self.current_msg:
                    print(
                        self.current_msg[TLV_FAIL_TAG])  # print error message

                client_logger.warning(
                    "Message did not have {}".format(TLV_ROLLDICERESULT_TAG))
示例#3
0
    def print_ingame_figure_choice(self, figures):
        """ Print figures that can be moved by the player
        @param figures:     (dict)  : num: figure_name
        """
        interface_msg = ""
        client_logger.debug(f"Figures: {str(figures)}")
        for num, figure in figures.items():
            interface_msg += f"{num}. : {figure}\n"  # !TODO handle select
        interface_msg += "0. EXIT : leave game\n"

        print(interface_msg)
示例#4
0
    def send_place_or_move_command(self):
        """Send place figure command to the server and anticipate positive response"""
        tlv_tag = self.get_ingame_options_tag()
        self.option_chosen = tlv_tag
        figure = "0"  # default value, if player wants to put figure we do not need information about figure number
        client_logger.debug("Options chosen: " + tlv_tag)
        if tlv_tag == TLV_MOVEFIGURE_TAG:
            figure = self.get_ingame_figure()

        data_dict = {tlv_tag: figure}

        client_logger.debug(
            "Place or Move command options chosen {}".format(data_dict))
        tlv = build_tlv_with_tags(data_dict)
        sendTlv(self.sock, tlv)
示例#5
0
    def get_ingame_figure(self):
        """ Should be called only if player chooses MOVE option """
        while True:
            figures = self.current_msg[TLV_OPTION_MOVE]  # only MOVE allowed
            client_logger.debug("Figures before deserialization: " +
                                str(figures))
            figures = deserialize_list(figures)
            client_logger.debug("Figures after deserialization: " +
                                str(figures))
            figures = {str(num + 1): fig
                       for num, fig in enumerate(figures)
                       }  # num: fig_name dict
            # client_logger.debug("Figures dict: " + str(figures))
            self.print_ingame_figure_choice(figures)

            msg = input(">> ")
            msg = msg.strip()
            # client_logger.debug(f"Input: {msg}")
            client_logger.debug(f"figures: {str(figures)}")
            # client_logger.debug(f"true/false: {msg not in figures}")
            if msg == "0":
                self.close()

            if msg not in figures:
                print("Input {} is invalid".format(msg))
                continue
            figure = figures[msg]
            # figure = self.handle_ingame_figure_choice_input(msg)
            return figure
示例#6
0
    def handle_answer(self, ans):
        """
        Handle response from the server. It can change state of the client e.g. game started or
        just print received information.
        ans     (dict)  : TLV: str
        """

        if TLV_STARTED_TAG in ans:
            client_logger.debug("Game started tag received")
            # print("Press enter to start a game")
            self.game_started = True

        if TLV_FINISHED_TAG in ans:
            self.game_started = False

        if TLV_INFO_TAG in ans:  # information message -> print it
            print("\n" + remove_tlv_padding(ans[TLV_INFO_TAG]))

        if TLV_MOVEORPLACE_TAG in ans:
            client_logger.debug("TLV_MOVEORPLACE_TAG received")

        if TLV_ROLLDICERESULT_TAG in ans:
            client_logger.debug("Roll dice result tag received")
            self.game_roll = ans[TLV_ROLLDICERESULT_TAG]
            self.game_rolled = True
示例#7
0
    def set_room(self):
        """
        Set room number in a loop. If non-int is passed from stdin or server send negative response then try again.
        If server sends back positive response then break and return None.
        """
        while True:
            room = input("Create or select existing channel\n> ")
            try:
                int(room)
                tlv = add_tlv_tag(TLV_ROOM_TAG, room)
                sendTlv(self.sock, tlv)

                if self.wait_for_ack():  # positive answer
                    print("Server answer: ", self.current_msg[TLV_OK_TAG]
                          )  # new msg is saved after wait_for_ack call
                    client_logger.debug("Joined room number {}".format(room))
                    return

                print("Server answer: ",
                      self.current_msg[TLV_FAIL_TAG])  # fail msg info

            except ValueError:
                client_logger.info("Try again")
示例#8
0
    def handle_ingame_options_input(self, msg):
        if msg.upper().strip() in [
                options_mapping[TLV_OPTION_PUT], "PLACE_FIGURE"
        ]:
            client_logger.debug("PLACE FIGURE CHOSEN")
            return TLV_PLACEFIGURE_TAG

        elif msg.upper().strip() in [
                options_mapping[TLV_OPTION_MOVE], "MOVE_FIGURE"
        ]:
            client_logger.debug("MOVE FIGURE CHOSEN")
            return TLV_MOVEFIGURE_TAG

        elif msg.upper().strip() in ["0", "EXIT"]:
            client_logger.debug("EXIT CHOSEN")
            self.handle_exit_command()
示例#9
0
    def get_ingame_options_tag(self):
        while True:
            self.print_ingame_options()

            msg = input(">> ")
            client_logger.debug("Player input: " + msg)
            if msg not in ('0', '1', '2'):
                print("Input {} is invalid".format(msg))
                continue

            client_logger.debug("Player options: " + str(self.player_options))
            if msg not in self.player_options.values():
                print("You cannot do that!")  # !TODO print description
                continue

            tlv_tag = self.handle_ingame_options_input(msg)
            client_logger.debug("Return ingame option: " + str(tlv_tag))
            return tlv_tag
示例#10
0
    def wait_for_ack(self):
        """
        Blocks until new msg is put into the Queue. Returns True if msg contains OK_TAG. Otherwise, if msg contains
        FAIL_TAG or any doesn't contain any control tag (OK/FAIL) it returns False.
        @return:    (bool)  : indicates status of the control msg
        """
        msg = self.pipeline.get()  # blocks here
        self.current_msg = msg  # msg can be read from outside of this method while it returns control information

        if TLV_OK_TAG in msg:
            client_logger.debug("Received OK_TAG")
            return True

        elif TLV_FAIL_TAG in msg:
            client_logger.debug("Received FAIL_TAG")
            return False

        else:
            client_logger.debug("Received unknown tags: {}".format(
                get_types(msg)))
            raise OSError(
                "Unknown tag received, while waiting for control tag")
示例#11
0
    def run(self):
        event = threading.Event()
        read_thread = threading.Thread(
            target=self.read_loop, args=(event, ),
            daemon=True)  # daemon will be closed with the main thread
        try:
            read_thread.start()
            self.set_nickname()
            client_logger.info("My nickname is {}".format(self.nickname))
            self.set_room()
            self.running = True
            self.print_options()

            while self.running and not event.is_set():
                if self.game_started:
                    self.reset_vars()

                    if self.game_client_turn:
                        input("Press enter to roll a dice")
                        self.send_roll_command()  # blocks
                        if self.skip_turn:
                            client_logger.info("Skipping turn")
                        else:
                            self.send_place_or_move_command()
                        # if self.game_roll is not None:      # can be?
                        # print("GAME roll is not null")

                        self.game_roll = None
                        self.game_client_turn = False
                        self.roll_command_requested = False
                        client_logger.info("Player {} turn ended".format(
                            self.nickname))

                    else:
                        self.wait_for_turn()
                else:
                    rs, _, _ = select.select([sys.stdin], [], [], 1)

                    if event.is_set():  # server error
                        break

                    if self.game_started:  # game started
                        client_logger.debug("Game started, ignore input")
                        continue

                    if not rs:  # timeout with no input
                        continue

                    msg = sys.stdin.readline()

                    if msg[-1] == '\n':  # remove newline character
                        msg = msg[:-1]

                    if not msg:  # enter pressed
                        print("Press enter to refresh: ", end="",
                              flush=True)  # terminal is waiting for new line
                        continue

                    self.handle_options_input(msg)
            # self.close()  # sys.exit() raises SystemExit so finally will be executed
            raise Exception()
        except KeyboardInterrupt:
            client_logger.warning("Keyboard interrupt")
            print("Closing...\n")
            self.running = False
            self.close()
        except (OSError, EOFError) as e:
            print("Server error")
            client_logger.error("Server error: " + str(e))
            self.running = False
            self.close()
        except Exception as e:
            print("Server error")
            client_logger.error("Exception: " + str(e))
            self.running = False
            self.close()