Misc: Make @more reply in batches when possible.

This commit is contained in:
Valentin Lorentz 2021-03-13 18:11:52 +01:00
parent bf90a7c94d
commit 7cb3ae12da
4 changed files with 65 additions and 13 deletions

View File

@ -393,8 +393,18 @@ class Misc(callbacks.Plugin):
msgs.reverse()
L[-number:] = []
if msgs:
for msg in msgs:
irc.queueMsg(msg)
if conf.supybot.protocols.irc.experimentalExtensions() \
and 'draft/multiline' in irc.state.capabilities_ack \
and len(msgs) > 1:
# If draft/multiline is available, use it.
# TODO: set concat=True. For now we can't, because every
# message has "(XX more messages)" at the end, so it would be
# unreadable if the messages were concatenated
irc.queueMultilineBatches(msgs, target=msgs[0].args[0],
targetNick=msg.nick, concat=False)
else:
for msg in msgs:
irc.queueMsg(msg)
else:
irc.error(_('That\'s all, there is no more.'))
more = wrap(more, [additional('seenNick')])

View File

@ -236,6 +236,47 @@ class MiscTestCase(ChannelPluginTestCase):
self.assertResponse('more',
"Error: That's all, there is no more.")
def testMoreBatch(self):
self.irc.state.capabilities_ack.add('batch')
self.irc.state.capabilities_ack.add('draft/multiline')
self.irc.state.capabilities_ls['draft/multiline'] = 'max-bytes=4096'
with conf.supybot.protocols.irc.experimentalExtensions.context(True):
with conf.supybot.plugins.Misc.mores.context(2):
self.assertResponse('echo %s' % ('abc '*400),
'abc '*112 + ' \x02(3 more messages)\x02')
self.irc.feedMsg(ircmsgs.privmsg(
self.channel, "@more", prefix=self.prefix))
# First message opens the batch
m = self.irc.takeMsg()
self.assertEqual(m.command, 'BATCH', m)
batch_name = m.args[0][1:]
self.assertEqual(
m, ircmsgs.IrcMsg(command='BATCH',
args=('+' + batch_name,
'draft/multiline', self.channel)))
# Second message, first PRIVMSG
m = self.irc.takeMsg()
self.assertEqual(
m, ircmsgs.IrcMsg(command='PRIVMSG',
args=(self.channel, "abc " * 112 + " \x02(2 more messages)\x02"),
server_tags={'batch': batch_name}))
# Third message, last PRIVMSG
m = self.irc.takeMsg()
self.assertEqual(
m, ircmsgs.IrcMsg(command='PRIVMSG',
args=(self.channel,
"abc " * 112 + " \x02(1 more message)\x02"),
server_tags={'batch': batch_name}))
# Last message, closes the batch
m = self.irc.takeMsg()
self.assertEqual(
m, ircmsgs.IrcMsg(command='BATCH', args=(
'-' + batch_name,)))
def testClearMores(self):
self.assertRegexp('echo %s' % ('abc'*700), 'more')
self.assertRegexp('more', 'more')

View File

@ -953,7 +953,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
self.args[self.counter] = s
self.evalArgs()
def _replyOverhead(self, target, msg):
def _replyOverhead(self, target, targetNick):
"""Returns the number of bytes added to a PRIVMSG payload, either by
Limnoria itself or by the server.
Ignores tag bytes, as they are accounted for separatly."""
@ -965,8 +965,8 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
+ len(' :')
+ len('\r\n')
)
if self.prefixNick:
overhead += len(msg.nick) + len(': ')
if self.prefixNick and targetNick is not None:
overhead += len(targetNick) + len(': ')
return overhead
def _sendReply(self, s, target, msg, sendImmediately, stripCtcp):
@ -1000,7 +1000,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
allowedLength = conf.get(conf.supybot.reply.mores.length,
channel=target, network=self.irc.network)
if not allowedLength: # 0 indicates this.
allowedLength = 512 - self._replyOverhead(target, msg)
allowedLength = 512 - self._replyOverhead(target, msg.nick)
maximumMores = conf.get(conf.supybot.reply.mores.maximum,
channel=target, network=self.irc.network)
maximumLength = allowedLength * maximumMores
@ -1066,7 +1066,8 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
# More than one message to send now, and we are allowed to use
# multiline batches, so let's do it
self.queueMultilineBatches(
instant_messages, target, allowedLength, sendImmediately)
instant_messages, target, msg.nick, concat=True,
allowedLength=allowedLength, sendImmediately=sendImmediately)
else:
for instant_msg in instant_messages:
sendMsg(instant_msg)
@ -1087,8 +1088,8 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
self._mores[msg.nick] = (private, msgs)
return response
def queueMultilineBatches(self, msgs, target, allowedLength=0,
sendImmediately=False):
def queueMultilineBatches(self, msgs, target, targetNick, concat,
allowedLength=0, sendImmediately=False):
"""Queues the msgs passed as argument in batches using draft/multiline
batches.
@ -1098,7 +1099,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
assert 'draft/multiline' in self.state.capabilities_ack
if not allowedLength: # 0 indicates this.
allowedLength = 512 - self._replyOverhead(target, msg)
allowedLength = 512 - self._replyOverhead(target, targetNick)
multiline_cap_values = ircutils.parseCapabilityKeyValue(
self.state.capabilities_ls['draft/multiline'])
@ -1126,7 +1127,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
continue # 'grouper' generates None at the end
assert 'batch' not in batch_msg.server_tags
batch_msg.server_tags['batch'] = batch_name
if i > 0:
if concat and i > 0:
# Tell clients not to add a newline after this
batch_msg.server_tags['draft/multiline-concat'] = None
batch.append(batch_msg)

View File

@ -1453,8 +1453,8 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
if msg:
if msg.command.upper() == 'BATCH':
if not conf.supybot.protocols.irc.experimentalExtensions():
log.error('Dropping outgoing batch.'
'supybot.protocols.irc.experimentalExtensions'
log.error('Dropping outgoing batch. '
'supybot.protocols.irc.experimentalExtensions '
'is disabled, so plugins should not send '
'batches. This is a bug, please report it.')
return None