Example #1
0
class PokerRoomWatcher(threading.Thread):
    def __init__(self, near, room_id, ui):
        self.ui = ui
        self.room_id = room_id
        self.near = near
        self.poker = Poker(near, room_id)
        self.player_id = None
        self.cards = []
        self.load()
        super().__init__()

    def load(self):
        # Load cards
        self.cards = load(self.filename("cards")) or []
        self.ui.cards = self.cards[:]

        # Load secret key
        self.secret_key = load(
            self.filename("secret_key")) or generate_secret_key()
        self.secret_key = int(self.secret_key)
        dump(self.filename("secret_key"), self.secret_key)

    def find_player_id(self):
        players = get(self.poker.deck_state(), 'Ok', 'players')

        if not self.near.account_id in players:
            logging.debug(
                f"{self.near.account_id} is not in game {self.room_id}. Found: {players}"
            )
            return True
        else:
            self.player_id = players.index(self.near.account_id)
            logging.debug(
                f"{self.near.account_id} playing in game {self.room_id}. Found {players}"
            )
            return False

    def update_state(self):
        self._state = self.poker.state()
        self._deck_state = self.poker.deck_state()
        self._poker_state = self.poker.poker_state()
        self._turn = self.poker.get_turn()
        self.ui.update_state(self.room_id, self._state, self._deck_state,
                             self._poker_state, self._turn)

    def is_deck_action(self):
        return get(self._state, 'Ok') == 'DeckAction'

    def check_deck_shuffling(self):
        if not self.is_deck_action():
            return

        index = get(self._deck_state, 'Ok', 'status', 'Shuffling')

        if index is None:
            return
        index = int(index)

        if index != self.player_id:
            return

        partial_shuffle = self.poker.get_partial_shuffle()["Ok"]
        delta = 2 if self.player_id == 0 else 0
        partial_shuffle = [int(value) + delta for value in partial_shuffle]
        partial_shuffle = encrypt_and_shuffle(partial_shuffle, self.secret_key)
        partial_shuffle = [str(value) for value in partial_shuffle]
        self.poker.submit_partial_shuffle(partial_shuffle)

    def filename(self, mode):
        node_env = os.environ.get("NODE_ENV", "")
        chain_enc = f"{self.near.node_url}-{self.near.contract}-{node_env}"
        suffix = hashlib.md5(chain_enc.encode()).hexdigest()[:8]
        return f"{self.near.account_id}-{self.room_id}-{mode}-{suffix}"

    def on_receive_card(self, card):
        if card in self.cards:
            return

        self.cards.append(card)
        dump(self.filename("cards"), self.cards)
        self.ui.update_card(self.room_id, card)

    def check_revealing(self):
        if not self.is_deck_action():
            return

        index = get(self._deck_state, 'Ok', 'status', 'Revealing', 'turn')

        if index is None:
            return

        index = int(index)

        if index != self.player_id:
            return

        progress = int(
            get(self._deck_state, 'Ok', 'status', 'Revealing', 'progress'))

        progress = str(partial_decrypt(progress, self.secret_key))

        if get(self._deck_state, 'Ok', 'status', 'Revealing',
               'receiver') == self.player_id:
            self.on_receive_card(int(progress) - 2)
            self.poker.finish_reveal()
        else:
            self.poker.submit_reveal_part(progress)

    def step(self):
        if self.player_id is None:
            if not self.find_player_id():
                return

        self.update_state()
        self.check_deck_shuffling()
        self.check_revealing()

    def run(self):
        time_to_sleep = 1.

        while True:
            self.step()
            time.sleep(time_to_sleep)