From fca4c755223af29a07949808a0671cae7458fd59 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Fri, 30 Jan 2026 19:21:10 +1300 Subject: [PATCH] Fix speedbump+retrigger interactions Send and then edit over speedbump should now just post the edit. Hopefully this doesn't have any negative consequences. --- src/d2m/actions/edit-message.js | 2 +- src/d2m/actions/speedbump.js | 33 ++++++++++++++++--- ...est.js => message-to-event.test.embeds.js} | 0 ...pk.test.js => message-to-event.test.pk.js} | 0 src/d2m/event-dispatcher.js | 8 +++-- 5 files changed, 35 insertions(+), 8 deletions(-) rename src/d2m/converters/{message-to-event.embeds.test.js => message-to-event.test.embeds.js} (100%) rename src/d2m/converters/{message-to-event.pk.test.js => message-to-event.test.pk.js} (100%) diff --git a/src/d2m/actions/edit-message.js b/src/d2m/actions/edit-message.js index 5970b59..57b8f41 100644 --- a/src/d2m/actions/edit-message.js +++ b/src/d2m/actions/edit-message.js @@ -21,7 +21,7 @@ const mreq = sync.require("../../matrix/mreq") async function editMessage(message, guild, row) { const historicalRoomOfMessage = from("message_room").join("historical_channel_room", "historical_room_index").where({message_id: message.id}).select("room_id").get() const currentRoom = from("channel_room").join("historical_channel_room", "room_id").where({channel_id: message.channel_id}).select("room_id", "historical_room_index").get() - assert(currentRoom) + if (!currentRoom) return if (historicalRoomOfMessage && historicalRoomOfMessage.room_id !== currentRoom.room_id) return // tombstoned rooms should not have new events (including edits) sent to them diff --git a/src/d2m/actions/speedbump.js b/src/d2m/actions/speedbump.js index 7c3109b..1a6ef63 100644 --- a/src/d2m/actions/speedbump.js +++ b/src/d2m/actions/speedbump.js @@ -4,6 +4,14 @@ const DiscordTypes = require("discord-api-types/v10") const passthrough = require("../../passthrough") const {discord, select, db} = passthrough +const DEBUG_SPEEDBUMP = false + +function debugSpeedbump(message) { + if (DEBUG_SPEEDBUMP) { + console.log(message) + } +} + const SPEEDBUMP_SPEED = 4000 // 4 seconds delay const SPEEDBUMP_UPDATE_FREQUENCY = 2 * 60 * 60 // 2 hours @@ -27,8 +35,8 @@ async function updateCache(channelID, lastChecked) { db.prepare("UPDATE channel_room SET speedbump_id = ?, speedbump_webhook_id = ?, speedbump_checked = ? WHERE channel_id = ?").run(foundApplication, foundWebhook, now, channelID) } -/** @type {Set} set of messageID */ -const bumping = new Set() +/** @type {Map} messageID -> number of gateway events currently bumping */ +const bumping = new Map() /** * Slow down a message. After it passes the speedbump, return whether it's okay or if it's been deleted. @@ -36,9 +44,26 @@ const bumping = new Set() * @returns whether it was deleted */ async function doSpeedbump(messageID) { - bumping.add(messageID) + let value = (bumping.get(messageID) ?? 0) + 1 + bumping.set(messageID, value) + debugSpeedbump(`[speedbump] WAIT ${messageID}++ = ${value}`) + await new Promise(resolve => setTimeout(resolve, SPEEDBUMP_SPEED)) - return !bumping.delete(messageID) + + if (!bumping.has(messageID)) { + debugSpeedbump(`[speedbump] DELETED ${messageID}`) + return true + } + value = bumping.get(messageID) - 1 + if (value === 0) { + debugSpeedbump(`[speedbump] OK ${messageID}-- = ${value}`) + bumping.delete(messageID) + return false + } else { + debugSpeedbump(`[speedbump] MULTI ${messageID}-- = ${value}`) + bumping.set(messageID, value) + return true + } } /** diff --git a/src/d2m/converters/message-to-event.embeds.test.js b/src/d2m/converters/message-to-event.test.embeds.js similarity index 100% rename from src/d2m/converters/message-to-event.embeds.test.js rename to src/d2m/converters/message-to-event.test.embeds.js diff --git a/src/d2m/converters/message-to-event.pk.test.js b/src/d2m/converters/message-to-event.test.pk.js similarity index 100% rename from src/d2m/converters/message-to-event.pk.test.js rename to src/d2m/converters/message-to-event.test.pk.js diff --git a/src/d2m/event-dispatcher.js b/src/d2m/event-dispatcher.js index 7c2e118..c25d1c6 100644 --- a/src/d2m/event-dispatcher.js +++ b/src/d2m/event-dispatcher.js @@ -274,7 +274,7 @@ module.exports = { // Based on looking at data they've sent me over the gateway, this is the best way to check for meaningful changes. // If the message content is a string then it includes all interesting fields and is meaningful. // Otherwise, if there are embeds, then the system generated URL preview embeds. - if (!(typeof data.content === "string" || "embeds" in data)) return + if (!(typeof data.content === "string" || "embeds" in data || "components" in data)) return if (dUtils.isEphemeralMessage(data)) return // Ephemeral messages are for the eyes of the receiver only! @@ -282,8 +282,10 @@ module.exports = { const {affected, row} = await speedbump.maybeDoSpeedbump(data.channel_id, data.id) if (affected) return - // Check that the sending-to room exists, and deal with Eventual Consistency(TM) - if (retrigger.eventNotFoundThenRetrigger(data.id, module.exports.MESSAGE_UPDATE, client, data)) return + if (!row) { + // Check that the sending-to room exists, and deal with Eventual Consistency(TM) + if (retrigger.eventNotFoundThenRetrigger(data.id, module.exports.MESSAGE_UPDATE, client, data)) return + } /** @type {DiscordTypes.GatewayMessageCreateDispatchData} */ // @ts-ignore