add error handler and message deleter
This commit is contained in:
		
							parent
							
								
									e3737997ec
								
							
						
					
					
						commit
						6de13338a8
					
				
					 3 changed files with 100 additions and 8 deletions
				
			
		
							
								
								
									
										29
									
								
								d2m/actions/delete-message.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								d2m/actions/delete-message.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ const utils = {
 | 
				
			||||||
		/** @type {typeof import("./event-dispatcher")} */
 | 
							/** @type {typeof import("./event-dispatcher")} */
 | 
				
			||||||
		const eventDispatcher = sync.require("./event-dispatcher")
 | 
							const eventDispatcher = sync.require("./event-dispatcher")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Client internals, keep track of the state we need
 | 
				
			||||||
		if (message.t === "READY") {
 | 
							if (message.t === "READY") {
 | 
				
			||||||
			if (client.ready) return
 | 
								if (client.ready) return
 | 
				
			||||||
			client.ready = true
 | 
								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") {
 | 
								} else if (message.t === "MESSAGE_UPDATE") {
 | 
				
			||||||
			eventDispatcher.onMessageCreate(client, message.d)
 | 
									eventDispatcher.onMessageUpdate(client, message.d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (message.t === "MESSAGE_UPDATE") {
 | 
								} else if (message.t === "MESSAGE_DELETE") {
 | 
				
			||||||
			eventDispatcher.onMessageUpdate(client, message.d)
 | 
									eventDispatcher.onMessageDelete(client, message.d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		} else if (message.t === "MESSAGE_REACTION_ADD") {
 | 
								} else if (message.t === "MESSAGE_REACTION_ADD") {
 | 
				
			||||||
			eventDispatcher.onReactionAdd(client, message.d)
 | 
									eventDispatcher.onReactionAdd(client, message.d)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (e) {
 | 
				
			||||||
 | 
								// Let OOYE try to handle errors too
 | 
				
			||||||
 | 
								eventDispatcher.onError(client, e, message)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,61 @@
 | 
				
			||||||
const assert = require("assert").strict
 | 
					const assert = require("assert").strict
 | 
				
			||||||
 | 
					const util = require("util")
 | 
				
			||||||
const {sync, db} = require("../passthrough")
 | 
					const {sync, db} = require("../passthrough")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {import("./actions/send-message")}) */
 | 
					/** @type {import("./actions/send-message")}) */
 | 
				
			||||||
const sendMessage = sync.require("./actions/send-message")
 | 
					const sendMessage = sync.require("./actions/send-message")
 | 
				
			||||||
/** @type {import("./actions/edit-message")}) */
 | 
					/** @type {import("./actions/edit-message")}) */
 | 
				
			||||||
const editMessage = sync.require("./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")}) */
 | 
					/** @type {import("./actions/add-reaction")}) */
 | 
				
			||||||
const addReaction = sync.require("./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
 | 
					// Grab Discord events we care about for the bridge, check them, and pass them on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					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 <strong>Bridged event from Discord not delivered</strong>"
 | 
				
			||||||
 | 
											+ `<br>Gateway event: ${gatewayMessage.t}`
 | 
				
			||||||
 | 
											+ `<pre>${stackLines.join("\n")}</pre>`
 | 
				
			||||||
 | 
											+ `<details><summary>Original payload</summary>`
 | 
				
			||||||
 | 
											+ `<pre>${util.inspect(gatewayMessage.d, false, 4, false)}</pre></details>`,
 | 
				
			||||||
 | 
										"m.mentions": {
 | 
				
			||||||
 | 
											user_ids: ["@cadence:cadence.moe"]
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param {import("./discord-client")} client
 | 
						 * @param {import("./discord-client")} client
 | 
				
			||||||
	 * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
 | 
						 * @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
 | 
				
			||||||
| 
						 | 
					@ -38,7 +82,7 @@ module.exports = {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	onMessageUpdate(client, data) {
 | 
						onMessageUpdate(client, data) {
 | 
				
			||||||
		if (data.webhook_id) {
 | 
							if (data.webhook_id) {
 | 
				
			||||||
			const row = db.prepare("SELECT webhook_id FROM webhook WHERE webhook_id = ?").pluck().get(message.webhook_id)
 | 
								const row = db.prepare("SELECT webhook_id FROM webhook WHERE webhook_id = ?").pluck().get(data.webhook_id)
 | 
				
			||||||
			if (row) {
 | 
								if (row) {
 | 
				
			||||||
				// The update was sent by the bridge's own webhook on discord. We don't want to reflect this back, so just drop it.
 | 
									// The update was sent by the bridge's own webhook on discord. We don't want to reflect this back, so just drop it.
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
| 
						 | 
					@ -67,5 +111,14 @@ module.exports = {
 | 
				
			||||||
		if (data.emoji.id !== null) return // TODO: image emoji reactions
 | 
							if (data.emoji.id !== null) return // TODO: image emoji reactions
 | 
				
			||||||
		console.log(data)
 | 
							console.log(data)
 | 
				
			||||||
		addReaction.addReaction(data)
 | 
							addReaction.addReaction(data)
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @param {import("./discord-client")} client
 | 
				
			||||||
 | 
						 * @param {import("discord-api-types/v10").GatewayMessageDeleteDispatchData} data
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						onMessageDelete(client, data) {
 | 
				
			||||||
 | 
							console.log(data)
 | 
				
			||||||
 | 
							deleteMessage.deleteMessage(data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue