mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-01 01:09:22 +01:00
Split Irc.reply() into _reply() to make 'networks.remote' actually thread-safe
Previously, the Irc.reply_lock check was in the reply() function itself: replacing it with another function checking for the same lock would delay execution, but then run the wrong reply() code if another module used irc.reply() while 'remote' was executing.
This commit is contained in:
parent
40fa4f71bc
commit
9d9b01839c
21
classes.py
21
classes.py
@ -62,7 +62,7 @@ class Irc(utils.DeprecatedAttributesObject):
|
||||
|
||||
self.connected = threading.Event()
|
||||
self.aborted = threading.Event()
|
||||
self.reply_lock = threading.Lock()
|
||||
self.reply_lock = threading.RLock()
|
||||
|
||||
self.pingTimer = None
|
||||
|
||||
@ -559,11 +559,12 @@ class Irc(utils.DeprecatedAttributesObject):
|
||||
# replies across relay.
|
||||
self.callHooks([source, cmd, {'target': target, 'text': text}])
|
||||
|
||||
def reply(self, text, notice=None, source=None, private=None, force_privmsg_in_private=False,
|
||||
def _reply(self, text, notice=None, source=None, private=None, force_privmsg_in_private=False,
|
||||
loopback=True):
|
||||
"""Replies to the last caller in the right context (channel or PM)."""
|
||||
|
||||
with self.reply_lock:
|
||||
"""
|
||||
Core of the reply() function - replies to the last caller in the right context
|
||||
(channel or PM).
|
||||
"""
|
||||
if private is None:
|
||||
# Allow using private replies as the default, if no explicit setting was given.
|
||||
private = conf.conf['bot'].get("prefer_private_replies")
|
||||
@ -581,6 +582,16 @@ class Irc(utils.DeprecatedAttributesObject):
|
||||
|
||||
self.msg(target, text, notice=notice, source=source, loopback=loopback)
|
||||
|
||||
def reply(self, *args, **kwargs):
|
||||
"""
|
||||
Replies to the last caller in the right context (channel or PM).
|
||||
|
||||
This function wraps around _reply() and can be monkey-patched in a thread-safe manner
|
||||
to temporarily redirect plugin output to another target.
|
||||
"""
|
||||
with self.reply_lock:
|
||||
self._reply(*args, **kwargs)
|
||||
|
||||
def error(self, text, **kwargs):
|
||||
"""Replies with an error to the last caller in the right context (channel or PM)."""
|
||||
# This is a stub to alias error to reply
|
||||
|
@ -103,19 +103,19 @@ def remote(irc, source, args):
|
||||
del kwargs['source']
|
||||
irc.reply(text, source=irc.pseudoclient.uid, **kwargs)
|
||||
|
||||
old_reply = remoteirc.reply
|
||||
old_reply = remoteirc._reply
|
||||
|
||||
with remoteirc.reply_lock:
|
||||
try: # Remotely call the command (use the PyLink client as a dummy user).
|
||||
# Override the remote irc.reply() to send replies HERE.
|
||||
log.debug('(%s) networks.remote: overriding reply() of IRC object %s', irc.name, netname)
|
||||
remoteirc.reply = types.MethodType(_remote_reply, remoteirc)
|
||||
remoteirc._reply = types.MethodType(_remote_reply, remoteirc)
|
||||
world.services[args.service].call_cmd(remoteirc, remoteirc.pseudoclient.uid,
|
||||
' '.join(args.command))
|
||||
finally:
|
||||
# Restore the original remoteirc.reply()
|
||||
log.debug('(%s) networks.remote: restoring reply() of IRC object %s', irc.name, netname)
|
||||
remoteirc.reply = old_reply
|
||||
remoteirc._reply = old_reply
|
||||
# Remove the identification override after we finish.
|
||||
remoteirc.pseudoclient.account = ''
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user