diff options
author | 2019-12-04 15:13:11 +0100 | |
---|---|---|
committer | 2019-12-04 15:20:48 +0100 | |
commit | 62fe183ce6d499f6b2129b91a35fd9d6f2632d3f (patch) | |
tree | f21aaa356a6dca4545f69e7ca95baa617f9afaa1 | |
parent | Make AoC channel ID configurable for testing environments (diff) |
Unlock AoC role to make announcements actually ping the users
The Advent of Code cog has a subscription system that allows members
to subscribe to a daily notification indicating the puzzle for that
day has become available. However, we introduces a more stringent
role mentionability policy that meant that the mentions did not
actually ping the members subscribed.
To solve this, I've made sure that the bot unlocks the role before
making the announcement using the `unlock_role` context manager. This
also means the role is automatically unlocked after the message is
sent.
In addition, I noticed that Seasonalbot was consistently announcing
the puzzle about 0.5 seconds early. I've correct this by adding a
second to the sleep delay. In addition, the bot now verifies that the
puzzle is available using a small HEAD request. While this does send
a request to the AoC server, it prevents multiple users from sending
unnecessary requests by following our link before the puzzle is
actually available.
-rw-r--r-- | bot/seasons/christmas/adventofcode.py | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/bot/seasons/christmas/adventofcode.py b/bot/seasons/christmas/adventofcode.py index 71da8d94..f2ec83df 100644 --- a/bot/seasons/christmas/adventofcode.py +++ b/bot/seasons/christmas/adventofcode.py @@ -15,6 +15,7 @@ from pytz import timezone from bot.constants import AdventOfCode as AocConfig, Channels, Colours, Emojis, Tokens, WHITELISTED_CHANNELS from bot.decorators import override_in_channel +from bot.utils import unlocked_role log = logging.getLogger(__name__) @@ -85,17 +86,42 @@ async def day_countdown(bot: commands.Bot) -> None: while is_in_advent(): tomorrow, time_left = time_left_to_aoc_midnight() - await asyncio.sleep(time_left.seconds) + # Correct `time_left.seconds` for the sleep we have after unlocking the role (-5) and adding + # a second (+1) as the bot is consistently ~0.5 seconds early in announcing the puzzles. + await asyncio.sleep(time_left.seconds - 4) - channel = bot.get_channel(Channels.seasonalbot_chat) + channel = bot.get_channel(Channels.advent_of_code) if not channel: log.error("Could not find the AoC channel to send notification in") break - await channel.send(f"<@&{AocConfig.role_id}> Good morning! Day {tomorrow.day} is ready to be attempted. " - f"View it online now at https://adventofcode.com/{AocConfig.year}/day/{tomorrow.day}" - f" (this link could take a few minutes to start working). Good luck!") + aoc_role = channel.guild.get_role(AocConfig.role_id) + if not aoc_role: + log.error("Could not find the AoC role to announce the daily puzzle") + break + + async with unlocked_role(aoc_role, delay=5): + puzzle_url = f"https://adventofcode.com/{AocConfig.year}/day/{tomorrow.day}" + + # Check if the puzzle is already available to prevent our members from spamming + # the puzzle page before it's available by making a small HEAD request. + for retry in range(1, 5): + log.debug(f"Checking if the puzzle is already available (attempt {retry}/4)") + async with bot.http_session.head(puzzle_url, raise_for_status=False) as resp: + if resp.status == 200: + log.debug("Puzzle is available; let's send an announcement message.") + break + log.debug(f"The puzzle is not yet available (status={resp.status})") + await asyncio.sleep(10) + else: + log.error("The puzzle does does not appear to be available at this time, canceling announcement") + break + + await channel.send( + f"{aoc_role.mention} Good morning! Day {tomorrow.day} is ready to be attempted. " + f"View it online now at {puzzle_url}. Good luck!" + ) # Wait a couple minutes so that if our sleep didn't sleep enough # time we don't end up announcing twice. @@ -122,10 +148,10 @@ class AdventOfCode(commands.Cog): self.status_task = None countdown_coro = day_countdown(self.bot) - self.countdown_task = asyncio.ensure_future(self.bot.loop.create_task(countdown_coro)) + self.countdown_task = self.bot.loop.create_task(countdown_coro) status_coro = countdown_status(self.bot) - self.status_task = asyncio.ensure_future(self.bot.loop.create_task(status_coro)) + self.status_task = self.bot.loop.create_task(status_coro) @commands.group(name="adventofcode", aliases=("aoc",), invoke_without_command=True) @override_in_channel(AOC_WHITELIST) @@ -422,6 +448,7 @@ class AdventOfCode(commands.Cog): def cog_unload(self) -> None: """Cancel season-related tasks on cog unload.""" + log.debug("Unloading the cog and canceling the background task.") self.countdown_task.cancel() self.status_task.cancel() |