From f11dca5376f723ec87ab09fd5a54ae32645a5052 Mon Sep 17 00:00:00 2001 From: Humorous Baby Date: Tue, 8 Jun 2021 03:22:14 -0400 Subject: [PATCH] coretasks: fix bad WHO loop, update querytype who_reqs, which is used to track WHO requests to the server, had flipped keys/values and was never getting cleared upon RPL_ENDOFWHO. Eventually, this would lead to an endless loop while the bot tried to get an unused "querytype" (randint) in order to track WHO replies. This unneccessary loop/check to ensure unique values for the query type was removed. A RPL_WHOREPLY includes the channel name in the response, so confirming that the querytype for a channel matched is sufficient. querytype should be unique _per purpose_. So, now a constant querytype is used for `coretasks` WHO(X) requests. Notes: According to [the closest thing to] official specs: https://github.com/ircv3/ircv3-specifications/issues/81#issue-30000475 querytypes should be useful to: > simplify scripting, in example one could pass a certain value in the query > and have that value "signal" back what is to be done with those replies. Also see: https://github.com/quakenet/snircd/blob/17c92003d376c70db674821e92f2880ba1587132/doc/readme.who#L154 https://github.com/quakenet/snircd/blob/17c92003d376c70db674821e92f2880ba1587132/doc/readme.who#L105 --- sopel/coretasks.py | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/sopel/coretasks.py b/sopel/coretasks.py index 5fe5d026ff..2adfad8378 100644 --- a/sopel/coretasks.py +++ b/sopel/coretasks.py @@ -28,7 +28,6 @@ import datetime import functools import logging -from random import randint import re import sys import time @@ -45,8 +44,13 @@ LOGGER = logging.getLogger(__name__) +CORE_QUERYTYPE = '999' +"""WHOX querytype to indicate requests/responses from coretasks. + +Other plugins should use a different querytype. +""" + batched_caps = {} -who_reqs = {} # Keeps track of reqs coming from this plugin, rather than others def setup(bot): @@ -698,14 +702,12 @@ def _remove_from_channel(bot, nick, channel): def _send_who(bot, channel): if 'WHOX' in bot.isupport: # WHOX syntax, see http://faerion.sourceforge.net/doc/irc/whox.var - # Needed for accounts in WHO replies. The random integer is a param - # to identify the reply as one from this command, because if someone - # else sent it, we have no fucking way to know what the format is. - rand = str(randint(0, 999)) - while rand in who_reqs: - rand = str(randint(0, 999)) - who_reqs[rand] = channel - bot.write(['WHO', channel, 'a%nuachtf,' + rand]) + # Needed for accounts in WHO replies. The `CORE_QUERYTYPE` parameter + # for WHO is used to identify the reply from the server and confirm + # that it has the requested format. WHO replies with different + # querytypes in the response were initiated elsewhere and will be + # ignored. + bot.write(['WHO', channel, 'a%nuachtf,' + CORE_QUERYTYPE]) else: # We might be on an old network, but we still care about keeping our # user list updated @@ -1243,8 +1245,9 @@ def account_notify(bot, trigger): @plugin.priority('medium') def recv_whox(bot, trigger): """Track ``WHO`` responses when ``WHOX`` is enabled.""" - if len(trigger.args) < 2 or trigger.args[1] not in who_reqs: + if len(trigger.args) < 2 or trigger.args[1] != CORE_QUERYTYPE: # Ignored, some plugin probably called WHO + LOGGER.debug("Ignoring WHO reply for channel '%s'; not queried by coretasks", trigger.args[1]) return if len(trigger.args) != 8: LOGGER.warning( @@ -1307,16 +1310,6 @@ def recv_who(bot, trigger): _record_who(bot, channel, user, host, nick, away=away, modes=modes) -@module.event(events.RPL_ENDOFWHO) -@plugin.thread(False) -@module.unblockable -@plugin.priority('medium') -def end_who(bot, trigger): - """Handle the end of a response to a ``WHO`` command (if needed).""" - if 'WHOX' in bot.isupport: - who_reqs.pop(trigger.args[1], None) - - @module.event('AWAY') @module.thread(False) @module.unblockable