diff --git a/src/d2m/discord-packets.js b/src/d2m/discord-packets.js
index c9424a4..017d50e 100644
--- a/src/d2m/discord-packets.js
+++ b/src/d2m/discord-packets.js
@@ -157,59 +157,17 @@ const utils = {
}
// Event dispatcher for OOYE bridge operations
- if (listen === "full") {
+ if (listen === "full" && message.t) {
try {
- if (message.t === "GUILD_UPDATE") {
- await eventDispatcher.onGuildUpdate(client, message.d)
-
- } else if (message.t === "GUILD_EMOJIS_UPDATE" || message.t === "GUILD_STICKERS_UPDATE") {
- await eventDispatcher.onExpressionsUpdate(client, message.d)
-
- } else if (message.t === "CHANNEL_UPDATE") {
- await eventDispatcher.onChannelOrThreadUpdate(client, message.d, false)
-
- } else if (message.t === "CHANNEL_PINS_UPDATE") {
- await eventDispatcher.onChannelPinsUpdate(client, message.d)
-
- } else if (message.t === "CHANNEL_DELETE") {
- await eventDispatcher.onChannelDelete(client, message.d)
-
- } else if (message.t === "THREAD_CREATE") {
- // @ts-ignore
- await eventDispatcher.onThreadCreate(client, message.d)
-
- } else if (message.t === "THREAD_UPDATE") {
- // @ts-ignore
- await eventDispatcher.onChannelOrThreadUpdate(client, message.d, true)
-
- } else if (message.t === "MESSAGE_CREATE") {
- await eventDispatcher.onMessageCreate(client, message.d)
-
- } else if (message.t === "MESSAGE_UPDATE") {
- await eventDispatcher.onMessageUpdate(client, message.d)
-
- } else if (message.t === "MESSAGE_DELETE") {
- await eventDispatcher.onMessageDelete(client, message.d)
-
- } else if (message.t === "MESSAGE_DELETE_BULK") {
- await eventDispatcher.onMessageDeleteBulk(client, message.d)
-
- } else if (message.t === "TYPING_START") {
- await eventDispatcher.onTypingStart(client, message.d)
-
- } else if (message.t === "MESSAGE_REACTION_ADD") {
- await eventDispatcher.onReactionAdd(client, message.d)
-
- } else if (message.t === "MESSAGE_REACTION_REMOVE" || message.t === "MESSAGE_REACTION_REMOVE_EMOJI" || message.t === "MESSAGE_REACTION_REMOVE_ALL") {
+ if (message.t === "MESSAGE_REACTION_REMOVE" || message.t === "MESSAGE_REACTION_REMOVE_EMOJI" || message.t === "MESSAGE_REACTION_REMOVE_ALL") {
await eventDispatcher.onSomeReactionsRemoved(client, message.d)
} else if (message.t === "INTERACTION_CREATE") {
await interactions.dispatchInteraction(message.d)
- } else if (message.t === "PRESENCE_UPDATE") {
- eventDispatcher.onPresenceUpdate(client, message.d)
+ } else if (message.t in eventDispatcher) {
+ await eventDispatcher[message.t](client, message.d)
}
-
} catch (e) {
// Let OOYE try to handle errors too
await eventDispatcher.onError(client, e, message)
diff --git a/src/d2m/event-dispatcher.js b/src/d2m/event-dispatcher.js
index b98abfc..63ef3e0 100644
--- a/src/d2m/event-dispatcher.js
+++ b/src/d2m/event-dispatcher.js
@@ -2,7 +2,6 @@
const assert = require("assert").strict
const DiscordTypes = require("discord-api-types/v10")
-const util = require("util")
const {sync, db, select, from} = require("../passthrough")
/** @type {import("./actions/send-message")}) */
@@ -27,8 +26,6 @@ const updatePins = sync.require("./actions/update-pins")
const api = sync.require("../matrix/api")
/** @type {import("../discord/utils")} */
const dUtils = sync.require("../discord/utils")
-/** @type {import("../m2d/converters/utils")} */
-const mxUtils = require("../m2d/converters/utils")
/** @type {import("./actions/speedbump")} */
const speedbump = sync.require("./actions/speedbump")
/** @type {import("./actions/retrigger")} */
@@ -42,8 +39,6 @@ const matrixEventDispatcher = sync.require("../m2d/event-dispatcher")
const Semaphore = require("@chriscdn/promise-semaphore")
const checkMissedPinsSema = new Semaphore()
-let lastReportedEvent = 0
-
// Grab Discord events we care about for the bridge, check them, and pass them on
module.exports = {
@@ -53,45 +48,14 @@ module.exports = {
* @param {import("cloudstorm").IGatewayMessage} gatewayMessage
*/
async 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, {depth: null})
-
- if (gatewayMessage.t === "TYPING_START") return
-
- if (Date.now() - lastReportedEvent < 5000) return
- lastReportedEvent = Date.now()
-
const channelID = gatewayMessage.d["channel_id"]
if (!channelID) return
const roomID = select("channel_room", "room_id", {channel_id: channelID}).pluck().get()
if (!roomID) return
- const builder = new mxUtils.MatrixStringBuilder()
- builder.addLine("\u26a0 Bridged event from Discord not delivered", "\u26a0 Bridged event from Discord not delivered")
- builder.addLine(`Gateway event: ${gatewayMessage.t}`)
+ if (gatewayMessage.t === "TYPING_START") return
- let errorIntroLine = e.toString()
- if (e.cause) {
- errorIntroLine += ` (cause: ${e.cause})`
- }
- builder.addLine(errorIntroLine)
-
- const stack = matrixEventDispatcher.stringifyErrorStack(e)
- builder.addLine(`Error trace:\n${stack}`, `Error trace
${stack}
`)
-
- builder.addLine("", `Original payload
${util.inspect(gatewayMessage.d, false, 4, false)}
`)
- await api.sendEvent(roomID, "m.room.message", {
- ...builder.get(),
- "moe.cadence.ooye.error": {
- source: "discord",
- payload: gatewayMessage
- },
- "m.mentions": {
- user_ids: ["@cadence:cadence.moe"]
- }
- })
+ await matrixEventDispatcher.sendError(roomID, "Discord", gatewayMessage.t, e, gatewayMessage.d)
},
/**
@@ -151,7 +115,7 @@ module.exports = {
backfill: true,
...messages[i]
}
- await module.exports.onMessageCreate(client, simulatedGatewayDispatchData)
+ await module.exports.MESSAGE_CREATE(client, simulatedGatewayDispatchData)
}
}
},
@@ -198,7 +162,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.APIThreadChannel} thread
*/
- async onThreadCreate(client, thread) {
+ async THREAD_CREATE(client, thread) {
const channelID = thread.parent_id || undefined
const parentRoomID = select("channel_room", "room_id", {channel_id: channelID}).pluck().get()
if (!parentRoomID) return // Not interested in a thread if we aren't interested in its wider channel (won't autocreate)
@@ -210,7 +174,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayGuildUpdateDispatchData} guild
*/
- async onGuildUpdate(client, guild) {
+ async GUILD_UPDATE(client, guild) {
const spaceID = select("guild_space", "space_id", {guild_id: guild.id}).pluck().get()
if (!spaceID) return
await createSpace.syncSpace(guild)
@@ -219,19 +183,26 @@ module.exports = {
/**
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayChannelUpdateDispatchData} channelOrThread
- * @param {boolean} isThread
*/
- async onChannelOrThreadUpdate(client, channelOrThread, isThread) {
+ async CHANNEL_UPDATE(client, channelOrThread) {
const roomID = select("channel_room", "room_id", {channel_id: channelOrThread.id}).pluck().get()
if (!roomID) return // No target room to update the data on
await createRoom.syncRoom(channelOrThread.id)
},
+ /**
+ * @param {import("./discord-client")} client
+ * @param {DiscordTypes.GatewayChannelUpdateDispatchData} thread
+ */
+ async THREAD_UPDATE(client, thread) {
+ await module.exports.CHANNEL_UPDATE(client, thread)
+ },
+
/**
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayChannelPinsUpdateDispatchData} data
*/
- async onChannelPinsUpdate(client, data) {
+ async CHANNEL_PINS_UPDATE(client, data) {
const roomID = select("channel_room", "room_id", {channel_id: data.channel_id}).pluck().get()
if (!roomID) return // No target room to update pins in
const convertedTimestamp = updatePins.convertTimestamp(data.last_pin_timestamp)
@@ -242,7 +213,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayChannelDeleteDispatchData} channel
*/
- async onChannelDelete(client, channel) {
+ async CHANNEL_DELETE(client, channel) {
const guildID = channel["guild_id"]
if (!guildID) return // channel must have been a DM channel or something
const roomID = select("channel_room", "room_id", {channel_id: channel.id}).pluck().get()
@@ -255,7 +226,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayMessageCreateDispatchData} message
*/
- async onMessageCreate(client, message) {
+ async MESSAGE_CREATE(client, message) {
if (message.author.username === "Deleted User") return // Nothing we can do for deleted users.
const channel = client.channels.get(message.channel_id)
if (!channel || !("guild_id" in channel) || !channel.guild_id) return // Nothing we can do in direct messages.
@@ -285,7 +256,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayMessageUpdateDispatchData} data
*/
- async onMessageUpdate(client, data) {
+ async MESSAGE_UPDATE(client, data) {
// 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.
@@ -303,7 +274,7 @@ module.exports = {
if (affected) return
// Check that the sending-to room exists, and deal with Eventual Consistency(TM)
- if (retrigger.eventNotFoundThenRetrigger(data.id, module.exports.onMessageUpdate, client, data)) return
+ if (retrigger.eventNotFoundThenRetrigger(data.id, module.exports.MESSAGE_UPDATE, client, data)) return
/** @type {DiscordTypes.GatewayMessageCreateDispatchData} */
// @ts-ignore
@@ -321,7 +292,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayMessageReactionAddDispatchData} data
*/
- async onReactionAdd(client, data) {
+ async MESSAGE_REACTION_ADD(client, data) {
if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix.
await addReaction.addReaction(data)
},
@@ -338,25 +309,25 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayMessageDeleteDispatchData} data
*/
- async onMessageDelete(client, data) {
+ async MESSAGE_DELETE(client, data) {
speedbump.onMessageDelete(data.id)
- if (retrigger.eventNotFoundThenRetrigger(data.id, module.exports.onMessageDelete, client, data)) return
+ if (retrigger.eventNotFoundThenRetrigger(data.id, module.exports.MESSAGE_DELETE, client, data)) return
await deleteMessage.deleteMessage(data)
},
- /**
+ /**
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayMessageDeleteBulkDispatchData} data
*/
- async onMessageDeleteBulk(client, data) {
- await deleteMessage.deleteMessageBulk(data)
- },
+ async MESSAGE_DELETE_BULK(client, data) {
+ await deleteMessage.deleteMessageBulk(data)
+ },
/**
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayTypingStartDispatchData} data
*/
- async onTypingStart(client, data) {
+ async TYPING_START(client, data) {
const roomID = select("channel_room", "room_id", {channel_id: data.channel_id}).pluck().get()
if (!roomID) return
const mxid = from("sim").join("sim_member", "mxid").where({user_id: data.user_id, room_id: roomID}).pluck("mxid").get()
@@ -369,9 +340,17 @@ module.exports = {
/**
* @param {import("./discord-client")} client
- * @param {DiscordTypes.GatewayGuildEmojisUpdateDispatchData | DiscordTypes.GatewayGuildStickersUpdateDispatchData} data
+ * @param {DiscordTypes.GatewayGuildEmojisUpdateDispatchData} data
*/
- async onExpressionsUpdate(client, data) {
+ async GUILD_EMOJIS_UPDATE(client, data) {
+ await createSpace.syncSpaceExpressions(data, false)
+ },
+
+ /**
+ * @param {import("./discord-client")} client
+ * @param {DiscordTypes.GatewayGuildStickersUpdateDispatchData} data
+ */
+ async GUILD_STICKERS_UPDATE(client, data) {
await createSpace.syncSpaceExpressions(data, false)
},
@@ -379,7 +358,7 @@ module.exports = {
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayPresenceUpdateDispatchData} data
*/
- onPresenceUpdate(client, data) {
+ PRESENCE_UPDATE(client, data) {
const status = data.status
if (!status) return
setPresence.presenceTracker.incomingPresence(data.user.id, data.guild_id, status)
diff --git a/src/m2d/event-dispatcher.js b/src/m2d/event-dispatcher.js
index 1bc97de..a55c326 100644
--- a/src/m2d/event-dispatcher.js
+++ b/src/m2d/event-dispatcher.js
@@ -42,7 +42,7 @@ function stringifyErrorStack(err, depth = 0) {
}
// add full stack trace if one exists, otherwise convert to string
- let stackLines = ( err?.stack ?? `${err}` ).replace(/^/gm, " ".repeat(depth)).trim().split("\n")
+ let stackLines = String(err?.stack ?? err).replace(/^/gm, " ".repeat(depth)).trim().split("\n")
let cloudstormLine = stackLines.findIndex(l => l.includes("/node_modules/cloudstorm/"))
if (cloudstormLine !== -1) {
stackLines = stackLines.slice(0, cloudstormLine - 2)
@@ -80,56 +80,72 @@ function stringifyErrorStack(err, depth = 0) {
return collapsed;
}
+/**
+ * @param {string} roomID
+ * @param {"Discord" | "Matrix"} source
+ * @param {any} type
+ * @param {any} e
+ * @param {any} payload
+ */
+async function sendError(roomID, source, type, e, payload) {
+ console.error(`Error while processing a ${type} ${source} event:`)
+ console.error(e)
+ console.dir(payload, {depth: null})
+
+ if (Date.now() - lastReportedEvent < 5000) return null
+ lastReportedEvent = Date.now()
+
+ let errorIntroLine = e.toString()
+ if (e.cause) {
+ errorIntroLine += ` (cause: ${e.cause})`
+ }
+
+ const builder = new utils.MatrixStringBuilder()
+
+ const cloudflareErrorTitle = errorIntroLine.match(/.*?
discord\.com \| ([^<]*)<\/title>/s)?.[1]
+ if (cloudflareErrorTitle) {
+ builder.addLine(
+ `\u26a0 Matrix event not delivered to Discord. Discord might be down right now. Cloudflare error: ${cloudflareErrorTitle}`,
+ `\u26a0 Matrix event not delivered to Discord
Discord might be down right now. Cloudflare error: ${cloudflareErrorTitle}`
+ )
+ } else {
+ // What
+ const what = source === "Discord" ? "Bridged event from Discord not delivered" : "Matrix event not delivered to Discord"
+ builder.addLine(`\u26a0 ${what}`, `\u26a0 ${what}`)
+
+ // Who
+ builder.addLine(`Event type: ${type}`)
+
+ // Why
+ builder.addLine(errorIntroLine)
+
+ // Where
+ const stack = stringifyErrorStack(e)
+ builder.addLine(`Error trace:\n${stack}`, `Error trace
${stack}
`)
+
+ // How
+ builder.addLine("", `Original payload
${util.inspect(payload, false, 4, false)}
`)
+ }
+
+ // Send
+ await api.sendEvent(roomID, "m.room.message", {
+ ...builder.get(),
+ "moe.cadence.ooye.error": {
+ source: source.toLowerCase(),
+ payload
+ },
+ "m.mentions": {
+ user_ids: ["@cadence:cadence.moe"]
+ }
+ })
+}
+
function guard(type, fn) {
return async function(event, ...args) {
try {
return await fn(event, ...args)
} catch (e) {
- console.error(`Exception while processing a ${type} Matrix event:`)
- console.dir(event, {depth: null})
-
- if (Date.now() - lastReportedEvent < 5000) return
- lastReportedEvent = Date.now()
-
- let errorIntroLine = e.toString()
- if (e.cause) {
- errorIntroLine += ` (cause: ${e.cause})`
- }
-
- const cloudflareErrorTitle = errorIntroLine.match(/.*?discord\.com \| ([^<]*)<\/title>/s)?.[1]
- if (cloudflareErrorTitle) {
- return api.sendEvent(event.room_id, "m.room.message", {
- msgtype: "m.text",
- body: `\u26a0 Matrix event not delivered to Discord. Cloudflare error: ${cloudflareErrorTitle}.`,
- format: "org.matrix.custom.html",
- formatted_body: `\u26a0 Matrix event not delivered to Discord
Cloudflare error: ${cloudflareErrorTitle}`,
- "moe.cadence.ooye.error": {
- source: "matrix",
- payload: event
- }
- })
- }
-
- const stack = stringifyErrorStack(e)
- api.sendEvent(event.room_id, "m.room.message", {
- msgtype: "m.text",
- body: "\u26a0 Matrix event not delivered to Discord. See formatted content for full details.",
- format: "org.matrix.custom.html",
- formatted_body: "\u26a0 Matrix event not delivered to Discord"
- + `
Event type: ${type}`
- + `
${errorIntroLine}`
- + `
Error trace
`
- + `${stack}
`
- + `Original payload
`
- + `${util.inspect(event, false, 4, false)}
`,
- "moe.cadence.ooye.error": {
- source: "matrix",
- payload: event
- },
- "m.mentions": {
- user_ids: ["@cadence:cadence.moe"]
- }
- })
+ await sendError(event.room_id, "Matrix", type, e, event)
}
}
}
@@ -356,3 +372,4 @@ async event => {
}))
module.exports.stringifyErrorStack = stringifyErrorStack
+module.exports.sendError = sendError