Example #1
0
def get_recent_matches(summoner_id, region):
    """
    Retrieves game data for last 10 games played by a summoner, given a summoner ID and region.

    This potentially executes several queries:
    -first, we get match history.
        -game stats
        -IDs of participants
    -then we make a list of summoner IDs that we don't have in the DB
        -this gets broken up into MAX_IDS chunks and each chunk is a queried as a single call for basic summoner data

    Since match history returns the last 10 games, and each game can have 9 other players
    (assuming non-hexakill mode) - that's 90 potentially unknown summoner IDs + 1 for the summoner in question,
    giving us 91 summoner IDs that we need to query.

    91 / 40 = 2.275 rounded up is 3 queries at most for summoner ID data.

    3 + 1 (for the initial match history call) = 4 calls at most.
    """

    #print 'get_recent_matches()', summoner_id, region

    recent = riot_api.get_recent_games(summoner_id, region)

    # First make a set of the associated summoner IDs (a set cannot have duplicate entries).
    unique_players = set()
    for g in recent['games']:
        if 'fellowPlayers' in g:
            for p in g['fellowPlayers']:
                unique_players.add(p['summonerId'])

    # Now we take note of any summoner IDs we already have cached (so we can remove them).
    to_remove = set()
    for p in unique_players:
        try:
            Summoner.objects.filter(region=region).get(summoner_id=p)
            to_remove.add(p)
        except ObjectDoesNotExist:
            pass

    # Remove the already cached summoner IDs from the working set.
    for p in to_remove:
        unique_players.remove(p)

    player_list = list(unique_players)  # make a list of the set, so we can call chunks() on it

    # Don't forget, we have to check for the summoner ID whose history we're examining as well!
    try:
        Summoner.objects.filter(region=region).get(summoner_id=summoner_id)
    except ObjectDoesNotExist:  # if it isn't cached, and it isn't in the list yet, add it
        if summoner_id not in player_list:
            player_list.append(summoner_id)

    query_list = list(chunks(player_list, MAX_IDS))  # query_list now holds a list of lists of at most MAX_ID elements

    # Now ask the API for info on summoners, at most MAX_ID at a time.
    #print 'Now asking for participants...'
    summoner_dto = []
    for i in query_list:
        summoner_dto.append(riot_api.get_summoners(ids=i, region=region))

    #print 'Done getting participants!'

    # TODO: This part is sometimes getting duplicate summoners! (fixed?)
    # Now put those summoner DTOs in the cache.
    for chunk in summoner_dto:
        for player in chunk:
            # for v in chunk[player]:
            #     print v, len(v)
            #print u'ADDING summoner {}'.format(chunk[player]['name'])
            summoner = Summoner(summoner_id=chunk[player]['id'],
                                name=chunk[player]['name'],
                                std_name=chunk[player]['name'].replace(' ', '').lower(),
                                profile_icon_id=chunk[player]['profileIconId'],
                                revision_date=chunk[player]['revisionDate'],
                                summoner_level=chunk[player]['summonerLevel'],
                                region=region)

            # Sometimes requests will go out synchronously for the same summoner.
            # This means the cache is not hit and a double query for a single summoner occurs.
            # Duplicate summoners are prevented via the unique_together constraint on summoner_id and region,
            # which will throw IntegrityError and prevent the dupe from being made.
            try:
                #print summoner.name, len(summoner.name)
                summoner.save()
            except IntegrityError:
                pass

    # Requires summoners (as well as all related field values) to be cached before-hand (summoner caching done above).
    for match in recent['games']:
        # first fill in the simple stuff
        game = Game(summoner_id=Summoner.objects.filter(region=region).get(summoner_id=summoner_id),
                    champion_id=Champion.objects.get(champion_id=match['championId']),
                    create_date=match['createDate'],
                    game_id=match['gameId'],
                    game_mode=match['gameMode'],
                    game_type=match['gameType'],
                    invalid=match['invalid'],
                    ip_earned=match['ipEarned'],
                    level=match['level'],
                    map_id=match['mapId'],
                    spell_1=SummonerSpell.objects.get(spell_id=match['spell1']),
                    spell_2=SummonerSpell.objects.get(spell_id=match['spell2']),
                    sub_type=match['subType'],
                    team_id=match['teamId'],
                    region=region,
                    champion_key=Champion.objects.get(champion_id=match['championId']).key)

        stats = RawStat()

        # Here we add stats that were returned (only stats that aren't None or 0 will be returned by API)
        for i in match['stats']:
            setattr(stats, inflection.underscore(i), match['stats'][i])

        stats.save()

        # associate the RawStat object with this game
        game.stats = stats

        game_saved = False

        # Ensures no dupes of Game (or any related objects).
        try:
            game.save()
            game_saved = True
        except IntegrityError:
            pass

        # if game saved, we're good and just need to add the participating players
        if game_saved:
            # associate each Player object with this game
            if 'fellowPlayers' in match:
                for p in match['fellowPlayers']:
                    player = Player(champion=Champion.objects.get(champion_id=p['championId']),
                                    summoner=Summoner.objects.filter(region=region).get(summoner_id=p['summonerId']),
                                    team_id=p['teamId'],
                                    participant_of=game)
                    player.save()
        else:  # if it didn't save, we can get rid of the stats object too.
            stats.delete()
Example #2
0
def get_recent_matches(summoner_id, region):
    """
    Retrieves game data for last 10 games played by a summoner, given a summoner ID and region.

    This potentially executes several queries:
    -first, we get match history.
        -game stats
        -IDs of participants
    -then we make a list of summoner IDs that we don't have in the DB
        -this gets broken up into MAX_IDS chunks and each chunk is a queried as a single call for basic summoner data

    Since match history returns the last 10 games, and each game can have 9 other players
    (assuming non-hexakill mode) - that's 90 potentially unknown summoner IDs + 1 for the summoner in question,
    giving us 91 summoner IDs that we need to query.

    91 / 40 = 2.275 rounded up is 3 queries at most for summoner ID data.

    3 + 1 (for the initial match history call) = 4 calls at most.
    """

    #print 'get_recent_matches()', summoner_id, region

    recent = riot_api.get_recent_games(summoner_id, region)

    # First make a set of the associated summoner IDs (a set cannot have duplicate entries).
    unique_players = set()
    for g in recent['games']:
        if 'fellowPlayers' in g:
            for p in g['fellowPlayers']:
                unique_players.add(p['summonerId'])

    # Now we take note of any summoner IDs we already have cached (so we can remove them).
    to_remove = set()
    for p in unique_players:
        try:
            Summoner.objects.filter(region=region).get(summoner_id=p)
            to_remove.add(p)
        except ObjectDoesNotExist:
            pass

    # Remove the already cached summoner IDs from the working set.
    for p in to_remove:
        unique_players.remove(p)

    player_list = list(
        unique_players
    )  # make a list of the set, so we can call chunks() on it

    # Don't forget, we have to check for the summoner ID whose history we're examining as well!
    try:
        Summoner.objects.filter(region=region).get(summoner_id=summoner_id)
    except ObjectDoesNotExist:  # if it isn't cached, and it isn't in the list yet, add it
        if summoner_id not in player_list:
            player_list.append(summoner_id)

    query_list = list(
        chunks(player_list, MAX_IDS)
    )  # query_list now holds a list of lists of at most MAX_ID elements

    # Now ask the API for info on summoners, at most MAX_ID at a time.
    #print 'Now asking for participants...'
    summoner_dto = []
    for i in query_list:
        summoner_dto.append(riot_api.get_summoners(ids=i, region=region))

    #print 'Done getting participants!'

    # TODO: This part is sometimes getting duplicate summoners! (fixed?)
    # Now put those summoner DTOs in the cache.
    for chunk in summoner_dto:
        for player in chunk:
            # for v in chunk[player]:
            #     print v, len(v)
            #print u'ADDING summoner {}'.format(chunk[player]['name'])
            summoner = Summoner(summoner_id=chunk[player]['id'],
                                name=chunk[player]['name'],
                                std_name=chunk[player]['name'].replace(
                                    ' ', '').lower(),
                                profile_icon_id=chunk[player]['profileIconId'],
                                revision_date=chunk[player]['revisionDate'],
                                summoner_level=chunk[player]['summonerLevel'],
                                region=region)

            # Sometimes requests will go out synchronously for the same summoner.
            # This means the cache is not hit and a double query for a single summoner occurs.
            # Duplicate summoners are prevented via the unique_together constraint on summoner_id and region,
            # which will throw IntegrityError and prevent the dupe from being made.
            try:
                #print summoner.name, len(summoner.name)
                summoner.save()
            except IntegrityError:
                pass

    # Requires summoners (as well as all related field values) to be cached before-hand (summoner caching done above).
    for match in recent['games']:
        # first fill in the simple stuff
        game = Game(
            summoner_id=Summoner.objects.filter(region=region).get(
                summoner_id=summoner_id),
            champion_id=Champion.objects.get(champion_id=match['championId']),
            create_date=match['createDate'],
            game_id=match['gameId'],
            game_mode=match['gameMode'],
            game_type=match['gameType'],
            invalid=match['invalid'],
            ip_earned=match['ipEarned'],
            level=match['level'],
            map_id=match['mapId'],
            spell_1=SummonerSpell.objects.get(spell_id=match['spell1']),
            spell_2=SummonerSpell.objects.get(spell_id=match['spell2']),
            sub_type=match['subType'],
            team_id=match['teamId'],
            region=region,
            champion_key=Champion.objects.get(
                champion_id=match['championId']).key)

        stats = RawStat()

        # Here we add stats that were returned (only stats that aren't None or 0 will be returned by API)
        for i in match['stats']:
            setattr(stats, inflection.underscore(i), match['stats'][i])

        stats.save()

        # associate the RawStat object with this game
        game.stats = stats

        game_saved = False

        # Ensures no dupes of Game (or any related objects).
        try:
            game.save()
            game_saved = True
        except IntegrityError:
            pass

        # if game saved, we're good and just need to add the participating players
        if game_saved:
            # associate each Player object with this game
            if 'fellowPlayers' in match:
                for p in match['fellowPlayers']:
                    player = Player(
                        champion=Champion.objects.get(
                            champion_id=p['championId']),
                        summoner=Summoner.objects.filter(region=region).get(
                            summoner_id=p['summonerId']),
                        team_id=p['teamId'],
                        participant_of=game)
                    player.save()
        else:  # if it didn't save, we can get rid of the stats object too.
            stats.delete()