Delay some channel handling operations

Specifically, the mode handling and the end of list modes are delayed until the end of the WHO reply from the server. When the end of the WHO reply is received, all queued operations on the channel, if any, are triggered at once in the form of relevant events.
This commit is contained in:
Vgr E. Barry 2016-11-17 10:01:25 -05:00
parent b180f99051
commit 074548813f
2 changed files with 27 additions and 6 deletions

View File

@ -67,6 +67,7 @@ class Channel(IRCContext):
self.modes = {}
self.timestamp = None
self.state = _States.NotJoined
self._pending = []
def __del__(self):
self.users.clear()
@ -81,6 +82,12 @@ class Channel(IRCContext):
def __repr__(self):
return "{self.__class__.__name__}({self.name!r})".format(self=self)
def queue(self, name, params, args):
if self._pending is None:
Event(name, params).dispatch(*args)
else:
self._pending.append((name, params, args))
def join(self, key=""):
if self.state in (_States.NotJoined, _States.Left):
self.state = _States.PendingJoin
@ -151,7 +158,7 @@ class Channel(IRCContext):
self.client.send("MODE", self.name, "".join(final))
def update_modes(self, rawnick, mode, targets):
def update_modes(self, actor, mode, targets):
"""Update the channel's mode registry with the new modes.
This is called whenever a MODE event is received. All of the
@ -184,7 +191,7 @@ class Channel(IRCContext):
elif c in list_modes: # stuff like bans, quiets, and ban and invite exempts
if c not in self.modes:
self.modes[c] = {}
self.modes[c][targets[i]] = (rawnick, set_time)
self.modes[c][targets[i]] = (actor.rawnick, set_time)
i += 1
else:

View File

@ -6,7 +6,7 @@ further in the relevant hook functions.
"""
from src.decorators import hook
from src.decorators import event_listener, hook
from src.context import Features
from src.events import Event
from src.logger import plog
@ -144,6 +144,16 @@ def end_who(cli, bot_server, bot_nick, target, rest):
"""
try:
chan = channels.get(target)
except KeyError:
pass
else:
if chan._pending is not None:
for name, params, args in chan._pending:
Event(name, params).dispatch(*args)
chan._pending = None
Event("who_end", {}).dispatch(var, target)
### Server PING handling
@ -278,9 +288,13 @@ def mode_change(cli, rawnick, chan, mode, *targets):
return
target = channels.add(chan, cli)
target.update_modes(rawnick, mode, targets)
target.queue("mode_change", {"mode": mode, "targets": targets}, (var, actor, target))
Event("mode_change", {}).dispatch(var, actor, target)
@event_listener("mode_change", 0) # This should fire before anything else!
def apply_mode_changes(evt, var, actor, target):
"""Apply all mode changes before any other event."""
target.update_modes(actor, evt.data.pop("mode"), evt.data.pop("targets"))
### List modes handling (bans, quiets, ban and invite exempts)
@ -369,7 +383,7 @@ def handle_endlistmode(cli, chan, mode):
"""Handle the end of a list mode listing."""
ch = channels.add(chan, cli)
Event("end_listmode", {}).dispatch(var, ch, mode)
ch.queue("end_listmode", {}, (var, ch, mode))
@hook("endofbanlist")
def end_banlist(cli, server, bot_nick, chan, message):