diff options
Diffstat (limited to 'bot/decorators.py')
-rw-r--r-- | bot/decorators.py | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/bot/decorators.py b/bot/decorators.py index 2520679a..874c811b 100644 --- a/bot/decorators.py +++ b/bot/decorators.py @@ -1,3 +1,4 @@ +import asyncio import functools import logging import random @@ -13,6 +14,8 @@ from discord.ext.commands import CheckFailure, Context from bot.constants import ERROR_REPLIES, Month +ONE_DAY = 24 * 60 * 60 + log = logging.getLogger(__name__) @@ -28,6 +31,42 @@ class InMonthCheckFailure(CheckFailure): pass +def seasonal_task(*allowed_months: Month, sleep_time: float = ONE_DAY) -> typing.Callable: + """ + Perform the decorated method periodically in `allowed_months`. + + This provides a convenience wrapper to avoid code repetition where some task shall + perform an operation repeatedly in a constant interval, but only in specific months. + + The decorated function will be called once every `sleep_time` seconds while + the current UTC month is in `allowed_months`. Sleep time defaults to 24 hours. + """ + def decorator(task_body: typing.Callable) -> typing.Callable: + @functools.wraps(task_body) + async def decorated_task(self: commands.Cog, *args, **kwargs) -> None: + """ + Call `task_body` once every `sleep_time` seconds in `allowed_months`. + + We assume `self` to be a Cog subclass instance carrying a `bot` attr. + As some tasks may rely on the client's cache to be ready, we delegate + to the bot to wait until it's ready. + """ + await self.bot.wait_until_ready() + log.info(f"Starting seasonal task {task_body.__qualname__} ({allowed_months})") + + while True: + current_month = Month(datetime.utcnow().month) + + if current_month in allowed_months: + await task_body(self, *args, **kwargs) + else: + log.debug(f"Seasonal task {task_body.__qualname__} sleeps in {current_month.name}") + + await asyncio.sleep(sleep_time) + return decorated_task + return decorator + + def in_month_listener(*allowed_months: Month) -> typing.Callable: """ Shield a listener from being invoked outside of `allowed_months`. |