Ejemplo n.º 1
0
def _get_all_data():
    return {
        '_ALL_MATCHES':
        MatchDB.dump_table(_ALL_MATCHES),
        '_USER_2_MATCH_ID':
        MatchDB.dump_table(_USER_2_MATCH_ID),
        '_PRIVATE_PENDING_MATCH_IDS':
        MatchDB.dump_table(_PRIVATE_PENDING_MATCH_IDS),
        '_PUBLIC_PENDING_MATCH_ID':
        MatchDB.get_queue(_PUBLIC_PENDING_MATCH_IDS, None)
    }
Ejemplo n.º 2
0
 def lock_and_get_chessboard(self):
     redis_lock, acquired = MatchDB.lock('chessboard', self.match_id,
                                         settings.GAME_TTL)
     if not acquired:
         return redis_lock, None
     else:
         return redis_lock, self.chessboard
Ejemplo n.º 3
0
def _create_match(player_uid1, join_token):
    match = Match(player_uid1, join_token)
    success = MatchDB.set(_USER_2_MATCH_ID,
                          player_uid1,
                          match.match_id,
                          xx=True)
    if not success:
        raise ValueError(
            'player {} should register before creating a match'.format(
                player_uid1))
    if join_token:
        success = MatchDB.set(_PRIVATE_PENDING_MATCH_IDS,
                              join_token,
                              match.match_id,
                              nx=True)
        if not success:
            raise exceptions.InvalidMatchState(
                'join_token {} is already in use by at least 2 players.'.
                format(join_token))
    else:
        MatchDB.enqueue(_PUBLIC_PENDING_MATCH_IDS, None, match.match_id)
    success = MatchDB.set(_ALL_MATCHES,
                          match.match_id,
                          match.to_dict(),
                          nx=True)
    if not success:
        raise exceptions.InvalidMatchState(
            'Match {} is already created'.format(match.match_id))
    chessboard = Chessboard()
    MatchDB.set(_CHESSBOARD, match.chessboard_id, chessboard.to_dict())
    return match
Ejemplo n.º 4
0
def join_match(player_uid, join_token):
    try:
        _register_player(player_uid, bool(join_token))
    except exceptions.AlreadyInMatchException:
        match_id = MatchDB.get(_USER_2_MATCH_ID, player_uid)
        match_dict = MatchDB.get(_ALL_MATCHES, match_id)
        if match_dict:
            match = Match.from_dict(match_dict)
            if match.join_token == join_token:
                return match
        leave_match(player_uid)
        _register_player(player_uid, bool(join_token))
    try:
        if join_token:
            blocking_timeout = min(settings.GAME_TTL // 2, 5)
            match_room_door, can_use_door = MatchDB.lock(
                'match_room_door',
                join_token,
                blocking_timeout=blocking_timeout)
            if not can_use_door:
                raise exceptions.CannotAcquireMatchDoor(
                    'the door {} is too crowded.'.format(join_token))
            population = MatchDB.enter_private_match(join_token)
            if population == 1:
                # going to create a match
                match_id = None
            elif population == 2:
                # going to join an existing match
                match_id = MatchDB.takeaway(_PRIVATE_PENDING_MATCH_IDS,
                                            join_token)
            elif population > 2:
                # join_token collision. try another join_token
                raise exceptions.InvalidMatchState(
                    'join_token {} is already in use by at least 2 players.'.
                    format(join_token))
        else:
            match_id = MatchDB.dequeue(_PUBLIC_PENDING_MATCH_IDS, None, False)
        if match_id is None:
            match = _create_match(player_uid, join_token)
        else:
            match = Match.from_dict(MatchDB.get(_ALL_MATCHES, match_id))
            match.set_player2(player_uid)
            MatchDB.set(_USER_2_MATCH_ID, player_uid, match.match_id)
            match.save()
        match.send_message_from(player_uid, msg_meta.MSG_TYPE_CONTROL,
                                msg_meta.MSG_CONST_JOIN)
        return match
    finally:
        if join_token:
            match_room_door.release()
Ejemplo n.º 5
0
def handle_reply_undo_request(message):
    msg_data = json.loads(message['msg_data'])
    match = match_driver.get_match(current_user.user_id)
    if not msg_data or not msg_data.get('approved'):
        msg_data = {'approved': False}
        match.send_message_from(current_user.user_id, MSG_TYPE_REPLYUNDOREQ,
                                msg_data)
        return msg_data
    try:
        lock, chessboard = match.lock_and_get_chessboard()
        if not chessboard:
            match.send_message_from(current_user.user_id,
                                    MSG_TYPE_REPLYUNDOREQ, msg_data)
            return msg_data
        step = chessboard.undo()
        if not step:
            match.send_message_from(current_user.user_id,
                                    MSG_TYPE_REPLYUNDOREQ, msg_data)
            return msg_data
        match.chessboard = chessboard
        step['undone_color'] = Chessman.id2color(step['chess_id']).value
        kill_chess_id = step['kill_chess_id']
        if kill_chess_id is not None:
            killed_color = Chessman.id2color(kill_chess_id)
            step['killed_color'] = killed_color.value
            step['killed_char'] = Chessman.role2char(
                Chessman.id2role(kill_chess_id), color=killed_color)
            step['killed_pic'] = Chessman.role2pic(
                Chessman.id2role(kill_chess_id), color=killed_color)
        msg_data = {'approved': True, 'step': step}
        match.send_message_from(current_user.user_id, MSG_TYPE_REPLYUNDOREQ,
                                msg_data)
        return msg_data
    finally:
        MatchDB.delete(
            'undoreq', "{}-{}".format(match.another_player_uid,
                                      match.match_id))
        lock.release()
Ejemplo n.º 6
0
def handle_draw_request(message):
    match = match_driver.get_match(current_user.user_id)
    if match.is_over:
        return {'result': False}
    # If your draw request within the past 60s was not approved, by the ohter
    # player, then you can't request again.
    can_request = MatchDB.set('drawreq',
                              "{}-{}".format(current_user.user_id,
                                             match.match_id),
                              'requesting',
                              nx=True,
                              ex=60)
    if not can_request:
        return {'result': False}
    msg_type = message['msg_type']
    msg_data = message['msg_data']
    match.send_message_from(current_user.user_id, msg_type, msg_data)
    return {'result': True}
Ejemplo n.º 7
0
def _register_player(user_id, is_public_game):
    success = MatchDB.set(_USER_2_MATCH_ID, user_id, is_public_game, nx=True)
    if not success:
        raise exceptions.AlreadyInMatchException()
Ejemplo n.º 8
0
def set_chessboard(chessboard_id, chessboard):
    return MatchDB.set(_CHESSBOARD, chessboard_id, chessboard.to_dict())
Ejemplo n.º 9
0
def get_chessboard(chessboard_id):
    return Chessboard.from_dict(MatchDB.get(_CHESSBOARD, chessboard_id))
Ejemplo n.º 10
0
def get_match(player_uid):
    match_id = MatchDB.get(_USER_2_MATCH_ID, player_uid)
    if not match_id:
        raise exceptions.NoMatchFoundException()
    return Match.from_dict(MatchDB.get(_ALL_MATCHES, match_id))
Ejemplo n.º 11
0
def saveMatch(match):
    MatchDB.set(_ALL_MATCHES, match.match_id, match.to_dict())
Ejemplo n.º 12
0
def leave_match(player_uid):
    blocking_timeout = min(settings.GAME_TTL // 2, 5)
    match_id = MatchDB.takeaway(_USER_2_MATCH_ID, player_uid)
    if not match_id:
        raise exceptions.InvalidMatchState(
            "Can't find the match_id for user {}.".format(player_uid))
    try:
        join_token = None
        match = Match.from_dict(MatchDB.get(_ALL_MATCHES, match_id))
        if not match:
            raise exceptions.InvalidMatchState(
                "Can't find the match {} to leave.".format(match_id))
        join_token = match.join_token
        if join_token:
            match_room_door, can_use_door = MatchDB.lock(
                'match_room_door',
                join_token,
                blocking_timeout=blocking_timeout)
            if not can_use_door:
                raise exceptions.CannotAcquireMatchDoor(
                    'the door {} is too crowded.'.format(join_token))

        match.remove_player(player_uid)
        MatchDB.delete(_USER_2_MATCH_ID, player_uid)
        if match.active_players_cnt == 1:
            match.send_message_from(player_uid, msg_meta.MSG_TYPE_CONTROL,
                                    msg_meta.MSG_CONST_LEFT)
            MatchDB.set(_ALL_MATCHES, match.match_id, match.to_dict())
            return
        # the last one leaving the match should clean up the mess
        match = Match.from_dict(MatchDB.takeaway(_ALL_MATCHES, match_id))
        if match.join_token:
            MatchDB.delete(_PRIVATE_PENDING_MATCH_IDS, match.join_token)
        else:
            MatchDB.force_remove_from_queue(_PUBLIC_PENDING_MATCH_IDS, None,
                                            match_id)
        MatchDB.delete(_CHESSBOARD, match.chessboard_id)
    finally:
        if join_token:
            match_room_door.release()
Ejemplo n.º 13
0
 def receive_message_to(self, my_uid):
     channel_name = self._channel_to(my_uid)
     message = MatchDB.dequeue('match_channel', channel_name, False)
     return message or {'msg_type': msg_meta.MSG_TYPE_NOP, 'msg_data': None}
Ejemplo n.º 14
0
 def send_message_from(self, my_uid, msg_type, msg_data):
     for other_uid in self.player_uids:
         if other_uid != my_uid:
             channel_name = self._channel_to(other_uid)
     message = {'msg_type': msg_type, 'msg_data': msg_data}
     MatchDB.enqueue('match_channel', channel_name, message)
Ejemplo n.º 15
0
 def get_message_queue_length(self, my_uid):
     channel_name = self._channel_to(my_uid)
     return MatchDB.queue_length('match_channel', channel_name)