irclib: 'lift' message tags to the batch when sending a multiline batch

This commit is contained in:
Valentin Lorentz 2021-03-13 19:00:41 +01:00
parent 92399bb6a7
commit bbc2e9de0d
2 changed files with 64 additions and 3 deletions

View File

@ -1114,19 +1114,31 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
# It's not optimal, but close enough and simplifies the code. # It's not optimal, but close enough and simplifies the code.
messages_per_batch = max_bytes_per_batch // allowedLength messages_per_batch = max_bytes_per_batch // allowedLength
# "Clients MUST NOT send tags other than draft/multiline-concat and
# batch on messages within the batch. In particular, all client-only
# tags associated with the message must be sent attached to the initial
# BATCH command."
# -- <https://ircv3.net/specs/extensions/multiline>
# So we copy the tags of the first message, discard the tags of all
# other messages, and apply the tags to the opening BATCH
server_tags = msgs[0].server_tags
for batch_msgs in utils.iter.grouper(msgs, messages_per_batch): for batch_msgs in utils.iter.grouper(msgs, messages_per_batch):
# TODO: should use sendBatch instead of queueBatch if # TODO: should use sendBatch instead of queueBatch if
# sendImmediately is True # sendImmediately is True
batch_name = ircutils.makeLabel() batch_name = ircutils.makeLabel()
batch = [] batch = []
batch.append(ircmsgs.IrcMsg(command='BATCH', args=( batch.append(ircmsgs.IrcMsg(command='BATCH',
'+' + batch_name, 'draft/multiline', target))) args=('+' + batch_name, 'draft/multiline', target),
server_tags=server_tags))
for (i, batch_msg) in enumerate(batch_msgs): for (i, batch_msg) in enumerate(batch_msgs):
if batch_msg is None: if batch_msg is None:
continue # 'grouper' generates None at the end continue # 'grouper' generates None at the end
assert 'batch' not in batch_msg.server_tags assert 'batch' not in batch_msg.server_tags
batch_msg.server_tags['batch'] = batch_name
# Discard the existing tags, and add the batch ones.
batch_msg.server_tags = {'batch': batch_name}
if concat and i > 0: if concat and i > 0:
# Tell clients not to add a newline after this # Tell clients not to add a newline after this
batch_msg.server_tags['draft/multiline-concat'] = None batch_msg.server_tags['draft/multiline-concat'] = None

View File

@ -699,9 +699,15 @@ class MultilinePrivmsgTestCase(ChannelPluginTestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Enable multiline
self.irc.state.capabilities_ack.add('batch') self.irc.state.capabilities_ack.add('batch')
self.irc.state.capabilities_ack.add('draft/multiline') self.irc.state.capabilities_ack.add('draft/multiline')
self.irc.state.capabilities_ls['draft/multiline'] = 'max-bytes=4096' self.irc.state.capabilities_ls['draft/multiline'] = 'max-bytes=4096'
# Enable msgid and +draft/reply
self.irc.state.capabilities_ack.add('message-tags')
conf.supybot.protocols.irc.experimentalExtensions.setValue(True) conf.supybot.protocols.irc.experimentalExtensions.setValue(True)
def tearDown(self): def tearDown(self):
@ -871,6 +877,49 @@ class MultilinePrivmsgTestCase(ChannelPluginTestCase):
m, ircmsgs.IrcMsg(command='BATCH', args=( m, ircmsgs.IrcMsg(command='BATCH', args=(
'-' + batch_name,))) '-' + batch_name,)))
def testReplyInstantBatchTags(self):
"""check a message's tags are 'lifted' to the initial BATCH
command."""
self.assertIsNone(self.irc.takeMsg())
conf.supybot.reply.mores.instant.setValue(2)
m = ircmsgs.privmsg(
self.channel, "@eval 'foo '*300", prefix=self.prefix)
m.server_tags['msgid'] = 'initialmsgid'
self.irc.feedMsg(m)
# 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),
server_tags={'+draft/reply': 'initialmsgid'}))
# Second message, first PRIVMSG
m = self.irc.takeMsg()
self.assertEqual(
m, ircmsgs.IrcMsg(command='PRIVMSG',
args=(self.channel, "test: '" + "foo " * 110),
server_tags={'batch': batch_name}))
# Third message, last PRIVMSG
m = self.irc.takeMsg()
self.assertEqual(
m, ircmsgs.IrcMsg(command='PRIVMSG',
args=(self.channel,
"test: " + "foo " * 111 + "\x02(1 more message)\x02"),
server_tags={'batch': batch_name,
'draft/multiline-concat': None}))
# Last message, closes the batch
m = self.irc.takeMsg()
self.assertEqual(
m, ircmsgs.IrcMsg(command='BATCH', args=(
'-' + batch_name,)))
class PluginRegexpTestCase(PluginTestCase): class PluginRegexpTestCase(PluginTestCase):
plugins = () plugins = ()