MSC Bot Devlog – Bot's Gone Crazy with User's Reactions

A couple days ago when we were giving a new member full member status, we discovered a hilarious bug with the MSC Bot.

The bot suddenly started spamming messages, as if it was executing the same command over and over again. The reason?

Whenever a reaction was added to or removed from a message, the bot treated it like it just received the message again!

The Issue

The change in the message stream doesn't really differentiate between a new/removed reaction to a message, and an entirely new message.

This is the “event” the bot receives when a reaction is added or removed from a message:

  _id: 'Adyuyjf8MvFcWixi9',
  rid: '738H9FSvBLGwSX5rS',
  msg: 'test emoji',
  ts: { '$date': 1587525487948 },
  u: {
    _id: 'XgHsc6JaAu9HgtaDb',
    username: 'PedoViking',
    name: 'OliverViking'
  _updatedAt: { '$date': 1587525494548 },
  mentions: [],
  channels: [],
  reactions: { ':rocket:': { usernames: [Array] } }

It's just the message object itself. How can the bot know that this is a reaction to a message? First one might think to check whether the reactions object is present, but that only solves half of the issue. Because when a reaction is removed, so that no reactions are present on the message anymore, the reactions object will be gone.

The Fix

It turned out to be quite a simple fix. Just had to switch the message handler (it attaches a callback to the changes in the message stream) out with a higher level message handler built into the JavaScript SDK.


  // Connect the processMessages callback


  // Connect the processMessages callback
  driver.respondToMessages(processMessages, {
    rooms: true,
    dm: true,
    edited: false,

This higher level message handler has a lot of built in checks. Most of them are configurable, as shown above. The developer can choose if they want the bot to respond to DMs, edited messages, and which rooms to respond to.

Why does this solve the issue though? How does respondToMessages handle filtering out emojis? Well, a quick look through the source code reveals that it actually just checks whether the message was created before the last message the bot received.

    // Set current time for comparison to incoming
    let currentReadTime = new Date(message.ts.$date)

    // Ignore edited messages if configured to
    if (!config.edited && message.editedAt) return

    // Set read time as time of edit, if message is edited
    if (message.editedAt) currentReadTime = new Date(message.editedAt.$date)

    // Ignore messages in stream that aren't new
    if (currentReadTime <= lastReadTime) return

#devlog #msc #code