ircquote: Use labeled-response when possible to reply to the user

This commit is contained in:
Valentin Lorentz 2023-06-04 22:47:46 +02:00 committed by Val Lorentz
parent 6021f0e6d9
commit ac84fa4d68
2 changed files with 106 additions and 1 deletions

View File

@ -93,6 +93,7 @@ class Owner(callbacks.Plugin):
self.__parent.__init__(irc) self.__parent.__init__(irc)
# Setup command flood detection. # Setup command flood detection.
self.commands = ircutils.FloodQueue(conf.supybot.abuse.flood.interval()) self.commands = ircutils.FloodQueue(conf.supybot.abuse.flood.interval())
self.ircquote_responses = utils.structures.ExpiringDict(600)
conf.supybot.abuse.flood.interval.addCallback(self.setFloodQueueTimeout) conf.supybot.abuse.flood.interval.addCallback(self.setFloodQueueTimeout)
# Setup plugins and default plugins for commands. # Setup plugins and default plugins for commands.
# #
@ -134,6 +135,31 @@ class Owner(callbacks.Plugin):
def callPrecedence(self, irc): def callPrecedence(self, irc):
return ([], [cb for cb in irc.callbacks if cb is not self]) return ([], [cb for cb in irc.callbacks if cb is not self])
def __call__(self, irc, msg):
ret = super().__call__(irc, msg)
if not self.ircquote_responses:
# short-path: if we have no ircquote in flight (which we don't,
# most of the time), then we can skip all the batch and
# label resolution.
return ret
try:
label = msg.server_tags.get("label")
if label and msg.command != "BATCH":
# if labeled-response BATCH, then it's handled in
# _doBatchIrcquote
ircquote_response = self.ircquote_responses.pop(
(irc.network, label), None)
if ircquote_response:
ircquote_response["irc"].reply(str(msg).strip())
except Exception as e:
self.log.exception("Errored while sending ircquote response")
finally:
return ret
def outFilter(self, irc, msg): def outFilter(self, irc, msg):
if msg.command == 'PRIVMSG' and not world.testing: if msg.command == 'PRIVMSG' and not world.testing:
if ircutils.strEqual(msg.args[0], irc.nick): if ircutils.strEqual(msg.args[0], irc.nick):
@ -229,6 +255,10 @@ class Owner(callbacks.Plugin):
self.commands.timeout = conf.supybot.abuse.flood.interval() self.commands.timeout = conf.supybot.abuse.flood.interval()
def doBatch(self, irc, msg): def doBatch(self, irc, msg):
self._doBatchMultiline(irc, msg)
self._doBatchIrcquote(irc, msg)
def _doBatchMultiline(self, irc, msg):
if not conf.supybot.protocols.irc.experimentalExtensions(): if not conf.supybot.protocols.irc.experimentalExtensions():
return return
@ -296,6 +326,30 @@ class Owner(callbacks.Plugin):
self._doPrivmsgs(irc, synthetic_msg) self._doPrivmsgs(irc, synthetic_msg)
def _doBatchIrcquote(self, irc, msg):
if not self.ircquote_responses:
# short-path: if we have no ircquote in flight (which we don't,
# most of the time), then we can skip all the batch and
# label resolution.
return
if not msg.args[0].startswith("-"):
return
batch = msg.tagged("batch")
label = batch.messages[0].server_tags.get("label")
if not label:
return
ircquote_response = self.ircquote_responses.pop(
(irc.network, label), None)
if ircquote_response:
ircquote_response["irc"].replies(
[str(msg).strip() for msg in batch.messages],
oneToOne=False
)
def doPrivmsg(self, irc, msg): def doPrivmsg(self, irc, msg):
if 'batch' in msg.server_tags: if 'batch' in msg.server_tags:
parent_batches = irc.state.getParentBatches(msg) parent_batches = irc.state.getParentBatches(msg)
@ -449,6 +503,10 @@ class Owner(callbacks.Plugin):
irc.error(utils.exnToString(e)) irc.error(utils.exnToString(e))
else: else:
irc.queueMsg(m) irc.queueMsg(m)
label = m.server_tags.get("label")
if label and "labeled-response" in irc.state.capabilities_ack:
self.ircquote_responses[(irc.network, label)] = {"irc": irc}
else:
irc.noReply() irc.noReply()
ircquote = wrap(ircquote, ['text']) ircquote = wrap(ircquote, ['text'])

View File

@ -48,6 +48,53 @@ class OwnerTestCase(PluginTestCase):
def testIrcquote(self): def testIrcquote(self):
self.assertResponse('ircquote PRIVMSG %s :foo' % self.irc.nick, 'foo') self.assertResponse('ircquote PRIVMSG %s :foo' % self.irc.nick, 'foo')
self.feedMsg('ircquote PING foo')
self.assertEqual(self.irc.takeMsg(), ircmsgs.IrcMsg(
command='PING', args=('foo',)))
def testIrcquoteLabeledResponse(self):
self.irc.state.capabilities_ack.update({'labeled-response', 'batch'})
self.feedMsg('ircquote @label=abc PING foo')
self.assertEqual(self.irc.takeMsg(), ircmsgs.IrcMsg(
server_tags={'label': 'abc'}, command='PING', args=('foo',)))
self.irc.feedMsg(ircmsgs.IrcMsg(
server_tags={'label': 'abc'}, prefix='server.',
command='PONG', args=('foo',)))
self.assertResponse(' ', '@label=abc :server. PONG :foo')
def testIrcquoteLabeledResponseBatch(self):
self.irc.state.capabilities_ack.update({'labeled-response', 'batch'})
self.feedMsg('ircquote @label=abc WHO val')
self.assertEqual(self.irc.takeMsg(), ircmsgs.IrcMsg(
server_tags={'label': 'abc'}, command='WHO', args=('val',)))
self.irc.feedMsg(ircmsgs.IrcMsg(
server_tags={'label': 'abc'}, prefix='server.',
command='BATCH', args=('+4', 'labeled-response')))
self.irc.feedMsg(ircmsgs.IrcMsg(
server_tags={'batch': '4'}, prefix='server.',
command='311', args=('test', 'val', '~u', 'host', '*', 'Val L')))
self.irc.feedMsg(ircmsgs.IrcMsg(
server_tags={'batch': '4'}, prefix='server.',
command='311', args=('test', 'val', '#limnoria-bots')))
# Batch not complete yet -> no response
self.assertIsNone(self.irc.takeMsg())
# end of batch
self.irc.feedMsg(ircmsgs.IrcMsg(
prefix='server.', command='BATCH', args=('-4',)))
self.assertResponse(
' ', '@label=abc :server. BATCH +4 :labeled-response')
self.assertResponse(
' ', '@batch=4 :server. 311 test val ~u host * :Val L')
self.assertResponse(
' ', '@batch=4 :server. 311 test val :#limnoria-bots')
self.assertResponse(
' ', ':server. BATCH :-4')
def testFlush(self): def testFlush(self):
self.assertNotError('flush') self.assertNotError('flush')