diff options
author | 2020-11-27 18:00:35 +0200 | |
---|---|---|
committer | 2020-11-27 18:00:35 +0200 | |
commit | bede07a6983a1d15461cd65914f41df624244dc3 (patch) | |
tree | 91a0bbc2d9728928fe477e3b299f3ccfbfb5beb9 /bot/exts/christmas/adventofcode.py | |
parent | Remove unnecessary check for members in leaderboard updater task (diff) |
Handle leaderboard cache create/update fail
Diffstat (limited to 'bot/exts/christmas/adventofcode.py')
-rw-r--r-- | bot/exts/christmas/adventofcode.py | 64 |
1 files changed, 52 insertions, 12 deletions
diff --git a/bot/exts/christmas/adventofcode.py b/bot/exts/christmas/adventofcode.py index 0d73eb3f..9d7289c2 100644 --- a/bot/exts/christmas/adventofcode.py +++ b/bot/exts/christmas/adventofcode.py @@ -3,6 +3,7 @@ import json import logging import math import re +import typing from datetime import datetime, timedelta from pathlib import Path from typing import List, Tuple @@ -202,6 +203,11 @@ class AdventOfCode(commands.Cog): for aoc_id, cookie in self.leaderboard_cookies.items() ] + # Check does this have any failed requests + if False in leaderboards: + log.warning("Unable to get one or more of the public leaderboards. Not updating cache.") + return + for leaderboard in leaderboards: for member_id, data in leaderboard["members"].items(): leaderboard_users[int(member_id)] = { @@ -281,15 +287,24 @@ class AdventOfCode(commands.Cog): async with self.staff_refresh_lock: secs = AocConfig.leaderboard_cache_age_threshold_seconds if self.staff_last_updated is None or self.staff_last_updated < datetime.utcnow() - timedelta(seconds=secs): - self.staff_last_updated = datetime.utcnow() - self.cached_staff_leaderboard = await AocPrivateLeaderboard.from_url( + leaderboard = await AocPrivateLeaderboard.from_url( AocConfig.leaderboard_staff_id, Tokens.aoc_staff_session_cookie ) - async def get_leaderboard(self, members_amount: int) -> str: + if leaderboard is not None: + self.staff_last_updated = datetime.utcnow() + self.cached_staff_leaderboard = leaderboard + else: + log.warning("Can't update staff leaderboard. Got unexpected response.") + + async def get_leaderboard(self, members_amount: int, context: commands.Context) -> typing.Union[str, bool]: """Generates leaderboard based on Redis data.""" - await self.check_leaderboard() + # When we don't have users in cache, log warning and return False. + if await self.public_user_data.length() == 0: + log.warning("Don't have cache for displaying AoC public leaderboard.") + return False + leaderboard_members = sorted( [json.loads(data) for user, data in await self.public_user_data.items()], key=lambda k: k["score"] )[:members_amount] @@ -446,10 +461,22 @@ class AdventOfCode(commands.Cog): if staff: await self.check_staff_leaderboard() - members_to_print = self.cached_staff_leaderboard.top_n(number_of_people_to_display) - table = AocPrivateLeaderboard.build_leaderboard_embed(members_to_print) + if self.cached_staff_leaderboard is not None: + members_to_print = self.cached_staff_leaderboard.top_n(number_of_people_to_display) + table = AocPrivateLeaderboard.build_leaderboard_embed(members_to_print) + else: + log.warning("Missing AoC staff leaderboard cache.") + table = False else: - table = await self.get_leaderboard(number_of_people_to_display) + await self.check_leaderboard() + table = await self.get_leaderboard(number_of_people_to_display, ctx) + + # When we don't have cache, show it to user. + if table is False: + await ctx.send( + ":x: Sorry, we can't get our leaderboard cache. Please let staff know about it." + ) + return # Build embed aoc_embed = discord.Embed( @@ -495,6 +522,9 @@ class AdventOfCode(commands.Cog): is_staff = ctx.channel.id == Channels.advent_of_code_staff if is_staff: await self.check_staff_leaderboard() + if self.cached_staff_leaderboard is None: + await ctx.send(":x: Missing leaderboard cache.") + return else: await self.check_leaderboard() @@ -503,6 +533,9 @@ class AdventOfCode(commands.Cog): total_members = len(self.cached_staff_leaderboard.members) else: total_members = await self.public_user_data.length() + if total_members == 0: + await ctx.send(":x: Missing leaderboard cache. Please notify staff about it.") + return _star = Emojis.star header = f"{'Day':4}{_star:^8}{_star*2:^4}{'% ' + _star:^8}{'% ' + _star*2:^4}\n{'='*35}" @@ -779,7 +812,7 @@ class AocPrivateLeaderboard: @staticmethod async def json_from_url( leaderboard_id: int, cookie: str, year: int = AocConfig.year - ) -> dict: + ) -> typing.Union[dict, bool]: """ Request the API JSON from Advent of Code for leaderboard_id for the specified year's event. @@ -791,10 +824,14 @@ class AocPrivateLeaderboard: async with aiohttp.ClientSession(headers=AOC_REQUEST_HEADER, cookies={"session": cookie}) as session: async with session.get(api_url) as resp: if resp.status == 200: - raw_dict = await resp.json() + try: + raw_dict = await resp.json() + except aiohttp.ContentTypeError: + log.warning(f"Got invalid response type from AoC API. Leaderboard ID {leaderboard_id}") + return False else: log.warning(f"Bad response received from AoC ({resp.status}), check session cookie") - resp.raise_for_status() + return False return raw_dict @@ -806,10 +843,13 @@ class AocPrivateLeaderboard: ) @classmethod - async def from_url(cls, leaderboard_id: int, cookie: str) -> "AocPrivateLeaderboard": + async def from_url(cls, leaderboard_id: int, cookie: str) -> typing.Union["AocPrivateLeaderboard", None]: """Helper wrapping of AocPrivateLeaderboard.json_from_url and AocPrivateLeaderboard.from_json.""" api_json = await cls.json_from_url(leaderboard_id, cookie) - return cls.from_json(api_json) + if api_json is not False: + return cls.from_json(api_json) + else: + return None @staticmethod def _sorted_members(injson: dict) -> list: |