forked from cadence/out-of-your-element
		
	Rework event dispatchers
This commit is contained in:
		
							parent
							
								
									c1592fcb95
								
							
						
					
					
						commit
						4cb99feeb2
					
				
					 3 changed files with 105 additions and 151 deletions
				
			
		| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 <strong>Bridged event from Discord not delivered</strong>")
 | 
			
		||||
		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}`, `<details><summary>Error trace</summary><pre>${stack}</pre></details>`)
 | 
			
		||||
 | 
			
		||||
		builder.addLine("", `<details><summary>Original payload</summary><pre>${util.inspect(gatewayMessage.d, false, 4, false)}</pre></details>`)
 | 
			
		||||
		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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(/<!DOCTYPE html>.*?<title>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 <strong>Matrix event not delivered to Discord</strong><br>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 <strong>${what}</strong>`)
 | 
			
		||||
 | 
			
		||||
		// Who
 | 
			
		||||
		builder.addLine(`Event type: ${type}`)
 | 
			
		||||
 | 
			
		||||
		// Why
 | 
			
		||||
		builder.addLine(errorIntroLine)
 | 
			
		||||
 | 
			
		||||
		// Where
 | 
			
		||||
		const stack = stringifyErrorStack(e)
 | 
			
		||||
		builder.addLine(`Error trace:\n${stack}`, `<details><summary>Error trace</summary><pre>${stack}</pre></details>`)
 | 
			
		||||
 | 
			
		||||
		// How
 | 
			
		||||
		builder.addLine("", `<details><summary>Original payload</summary><pre>${util.inspect(payload, false, 4, false)}</pre></details>`)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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(/<!DOCTYPE html>.*?<title>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 <strong>Matrix event not delivered to Discord</strong><br>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 <strong>Matrix event not delivered to Discord</strong>"
 | 
			
		||||
					+ `<br>Event type: ${type}`
 | 
			
		||||
					+ `<br>${errorIntroLine}`
 | 
			
		||||
					+ `<br><details><summary>Error trace</summary>`
 | 
			
		||||
					+ `<pre>${stack}</pre></details>`
 | 
			
		||||
					+ `<details><summary>Original payload</summary>`
 | 
			
		||||
					+ `<pre>${util.inspect(event, false, 4, false)}</pre></details>`,
 | 
			
		||||
				"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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue