diff --git a/d2m/actions/delete-message.js b/d2m/actions/delete-message.js
new file mode 100644
index 00000000..261c8f9d
--- /dev/null
+++ b/d2m/actions/delete-message.js
@@ -0,0 +1,29 @@
+// @ts-check
+
+const passthrough = require("../../passthrough")
+const { sync, db } = passthrough
+/** @type {import("../converters/edit-to-changes")} */
+const editToChanges = sync.require("../converters/edit-to-changes")
+/** @type {import("../../matrix/api")} */
+const api = sync.require("../../matrix/api")
+
+/**
+ * @param {import("discord-api-types/v10").GatewayMessageDeleteDispatchData} data
+ */
+async function deleteMessage(data) {
+ /** @type {string?} */
+ const roomID = db.prepare("SELECT channel_id FROM channel_room WHERE channel_id = ?").pluck().get(data.channel_id)
+ if (!roomID) return
+
+ /** @type {string[]} */
+ const eventsToRedact = db.prepare("SELECT event_id FROM event_message WHERE message_id = ?").pluck().all(data.id)
+
+ for (const eventID of eventsToRedact) {
+ // Unfortuately, we can't specify a sender to do the redaction as, unless we find out that info via the audit logs
+ await api.redactEvent(roomID, eventID)
+ db.prepare("DELETE from event_message WHERE event_id = ?").run(eventID)
+ // TODO: Consider whether this code could be reused between edited messages and deleted messages.
+ }
+}
+
+module.exports.deleteMessage = deleteMessage
diff --git a/d2m/discord-packets.js b/d2m/discord-packets.js
index b8c0af6d..6ae1c22b 100644
--- a/d2m/discord-packets.js
+++ b/d2m/discord-packets.js
@@ -16,6 +16,7 @@ const utils = {
/** @type {typeof import("./event-dispatcher")} */
const eventDispatcher = sync.require("./event-dispatcher")
+ // Client internals, keep track of the state we need
if (message.t === "READY") {
if (client.ready) return
client.ready = true
@@ -62,16 +63,25 @@ const utils = {
}
}
}
+ }
+ // Event dispatcher for OOYE bridge operations
+ try {
+ if (message.t === "MESSAGE_CREATE") {
+ eventDispatcher.onMessageCreate(client, message.d)
- } else if (message.t === "MESSAGE_CREATE") {
- eventDispatcher.onMessageCreate(client, message.d)
+ } else if (message.t === "MESSAGE_UPDATE") {
+ eventDispatcher.onMessageUpdate(client, message.d)
- } else if (message.t === "MESSAGE_UPDATE") {
- eventDispatcher.onMessageUpdate(client, message.d)
+ } else if (message.t === "MESSAGE_DELETE") {
+ eventDispatcher.onMessageDelete(client, message.d)
- } else if (message.t === "MESSAGE_REACTION_ADD") {
- eventDispatcher.onReactionAdd(client, message.d)
+ } else if (message.t === "MESSAGE_REACTION_ADD") {
+ eventDispatcher.onReactionAdd(client, message.d)
+ }
+ } catch (e) {
+ // Let OOYE try to handle errors too
+ eventDispatcher.onError(client, e, message)
}
}
}
diff --git a/d2m/event-dispatcher.js b/d2m/event-dispatcher.js
index 1527b28b..fde228d4 100644
--- a/d2m/event-dispatcher.js
+++ b/d2m/event-dispatcher.js
@@ -1,17 +1,61 @@
const assert = require("assert").strict
+const util = require("util")
const {sync, db} = require("../passthrough")
/** @type {import("./actions/send-message")}) */
const sendMessage = sync.require("./actions/send-message")
/** @type {import("./actions/edit-message")}) */
const editMessage = sync.require("./actions/edit-message")
-
+/** @type {import("./actions/delete-message")}) */
+const deleteMessage = sync.require("./actions/delete-message")
/** @type {import("./actions/add-reaction")}) */
const addReaction = sync.require("./actions/add-reaction")
+/** @type {import("../matrix/api")}) */
+const api = sync.require("../matrix/api")
+
+let lastReportedEvent = 0
// Grab Discord events we care about for the bridge, check them, and pass them on
module.exports = {
+ /**
+ * @param {import("./discord-client")} client
+ * @param {Error} e
+ * @param {import("cloudstorm").IGatewayMessage} gatewayMessage
+ */
+ onError(client, e, gatewayMessage) {
+ console.error("hit event-dispatcher's error handler with this exception:")
+ console.error(e) // TODO: also log errors into a file or into the database, maybe use a library for this? or just wing it? definitely need to be able to store the formatted event body to load back in later
+ console.error(`while handling this ${gatewayMessage.t} gateway event:`)
+ console.dir(gatewayMessage.d)
+
+ if (Date.now() - lastReportedEvent > 5000) {
+ lastReportedEvent = Date.now()
+ const channelID = gatewayMessage.d.channel_id
+ if (channelID) {
+ const roomID = db.prepare("SELECT room_id FROM channel_room WHERE channel_id = ?").pluck().get(channelID)
+ let stackLines = e.stack.split("\n")
+ let cloudstormLine = stackLines.findIndex(l => l.includes("/node_modules/cloudstorm/"))
+ if (cloudstormLine !== -1) {
+ stackLines = stackLines.slice(0, cloudstormLine - 2)
+ }
+ api.sendEvent(roomID, "m.room.message", {
+ msgtype: "m.text",
+ body: "\u26a0 Bridged event from Discord not delivered. See formatted content for full details.",
+ format: "org.matrix.custom.html",
+ formatted_body: "\u26a0 Bridged event from Discord not delivered"
+ + `
Gateway event: ${gatewayMessage.t}`
+ + `
${stackLines.join("\n")}` + + `
${util.inspect(gatewayMessage.d, false, 4, false)}