diff options
author | 2021-03-30 11:47:36 -0700 | |
---|---|---|
committer | 2021-03-30 12:07:58 -0700 | |
commit | feb9b22a40e311807eca5be58de04d0d95e85554 (patch) | |
tree | 83dd905dbc2b647e6fd13e80a46cd7272b5c03f2 | |
parent | HelpChannels: use aware datetimes everywhere (diff) |
HelpChannels: refactor get_closing_time
-rw-r--r-- | bot/exts/help_channels/_caches.py | 5 | ||||
-rw-r--r-- | bot/exts/help_channels/_channel.py | 80 | ||||
-rw-r--r-- | bot/exts/help_channels/_cog.py | 1 |
3 files changed, 43 insertions, 43 deletions
diff --git a/bot/exts/help_channels/_caches.py b/bot/exts/help_channels/_caches.py index 834c5f4c2..e741fd20f 100644 --- a/bot/exts/help_channels/_caches.py +++ b/bot/exts/help_channels/_caches.py @@ -12,9 +12,8 @@ claimants = RedisCache(namespace="HelpChannels.help_channel_claimants") # RedisCache[discord.TextChannel.id, UtcPosixTimestamp] claimant_last_message_times = RedisCache(namespace="HelpChannels.claimant_last_message_times") -# This cache maps a help channel to the timestamp of the last, non-claimant, -# message. This cache being empty for a given help channel indicates the -# question is unanswered. +# This cache maps a help channel to the timestamp of the last non-claimant message. +# This cache being empty for a given help channel indicates the question is unanswered. # RedisCache[discord.TextChannel.id, UtcPosixTimestamp] non_claimant_last_message_times = RedisCache(namespace="HelpChannels.non_claimant_last_message_times") diff --git a/bot/exts/help_channels/_channel.py b/bot/exts/help_channels/_channel.py index 719d341bd..8af059830 100644 --- a/bot/exts/help_channels/_channel.py +++ b/bot/exts/help_channels/_channel.py @@ -28,65 +28,67 @@ def get_category_channels(category: discord.CategoryChannel) -> t.Iterable[disco async def get_closing_time(channel: discord.TextChannel, init_done: bool) -> t.Tuple[Arrow, str]: - """Return the time at which the given help `channel` should be closed along with the reason.""" + """ + Return the time at which the given help `channel` should be closed along with the reason. + + `init_done` is True if the cog has finished loading and False otherwise. + + The time is calculated as follows: + + * If `init_done` is True or the cached time for the claimant's last message is unavailable, + add the configured `idle_minutes_claimant` to the time the most recent message was sent. + * If the help session is empty (see `is_empty`), do the above but with `deleted_idle_minutes`. + * If either of the above is attempted but the channel is completely empty, close the channel + immediately. + * Otherwise, retrieve the times of the claimant's and non-claimant's last messages from the + cache. Add the configured `idle_minutes_claimant` and idle_minutes_others`, respectively, and + choose the time which is furthest in the future. + """ log.trace(f"Getting the closing time for #{channel} ({channel.id}).") is_empty = await _message.is_empty(channel) - if is_empty: idle_minutes_claimant = constants.HelpChannels.deleted_idle_minutes else: idle_minutes_claimant = constants.HelpChannels.idle_minutes_claimant - claimant_last_message_time = await _caches.claimant_last_message_times.get(channel.id) - - if ( - is_empty - or not init_done - or claimant_last_message_time is None - ): - # If the current help channel has no messages, the help system cog is starting or - # the claimant cache is empty, use the last message in the channel to determine closing time instead. + claimant_time = await _caches.claimant_last_message_times.get(channel.id) + # The current session lacks messages, the cog is still starting, or the cache is empty. + if is_empty or not init_done or claimant_time is None: msg = await _message.get_last_message(channel) - if not msg: - # Last message can't be retrieved, return datetime.min so channel closes right now. log.debug(f"No idle time available; #{channel} ({channel.id}) has no messages, closing now.") return Arrow.min, "deleted" - # The time at which a channel should be closed. + # Use the greatest offset to avoid the possibility of prematurely closing the channel. time = Arrow.fromdatetime(msg.created_at) + timedelta(minutes=idle_minutes_claimant) return time, "latest_message" - # Switch to datetime objects so we can use time deltas - claimant_last_message_time = Arrow.utcfromtimestamp(claimant_last_message_time) - non_claimant_last_message_time = await _caches.non_claimant_last_message_times.get(channel.id) + claimant_time = Arrow.utcfromtimestamp(claimant_time) + others_time = await _caches.non_claimant_last_message_times.get(channel.id) - if non_claimant_last_message_time: - non_claimant_last_message_time = Arrow.utcfromtimestamp(non_claimant_last_message_time) + if others_time: + others_time = Arrow.utcfromtimestamp(others_time) else: - # If it's falsey, then it indicates a non-claimant has yet to reply to this session. - # Set to min date time so it isn't considered when calculating the closing time. - non_claimant_last_message_time = Arrow.min - - # Get the later time at which a channel should be closed - non_claimant_last_message_time += timedelta(minutes=constants.HelpChannels.idle_minutes_others) - claimant_last_message_time += timedelta(minutes=idle_minutes_claimant) - - # The further away closing time is what we should use. - if claimant_last_message_time >= non_claimant_last_message_time: - log.trace( - f"#{channel} ({channel.id}) should be closed at " - f"{claimant_last_message_time} due to claimant timeout." - ) - return claimant_last_message_time, "claimant_timeout" + # The help session hasn't received any answers (messages from non-claimants) yet. + # Set to min value so it isn't considered when calculating the closing time. + others_time = Arrow.min + + # Offset the cached times by the configured values. + others_time += timedelta(minutes=constants.HelpChannels.idle_minutes_others) + claimant_time += timedelta(minutes=idle_minutes_claimant) + + # Use the time which is the furthest into the future. + if claimant_time >= others_time: + closing_time = claimant_time + reason = "claimant_timeout" else: - log.trace( - f"#{channel} ({channel.id}) should be closed at " - f"{non_claimant_last_message_time} due to others timeout." - ) - return non_claimant_last_message_time, "others_timeout" + closing_time = others_time + reason = "others_timeout" + + log.trace(f"#{channel} ({channel.id}) should be closed at {closing_time} due to {reason}.") + return closing_time, reason async def get_in_use_time(channel_id: int) -> t.Optional[timedelta]: diff --git a/bot/exts/help_channels/_cog.py b/bot/exts/help_channels/_cog.py index 832c9cd84..183ee8a9b 100644 --- a/bot/exts/help_channels/_cog.py +++ b/bot/exts/help_channels/_cog.py @@ -303,7 +303,6 @@ class HelpChannels(commands.Cog): # Closing time is in the past. # Add 1 second due to POSIX timestamps being lower resolution than datetime objects. if closing_time < (arrow.utcnow() + timedelta(seconds=1)): - log.info( f"#{channel} ({channel.id}) is idle past {closing_time} " f"and will be made dormant. Reason: {closed_on}" |