Compare commits

..

2 commits

3 changed files with 58 additions and 21 deletions

View file

@ -1,7 +1,7 @@
// @ts-check // @ts-check
const passthrough = require("../../passthrough") const passthrough = require("../../passthrough")
const {sync, db, select} = passthrough const {sync, db, select, from} = passthrough
/** @type {import("../../matrix/api")} */ /** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api") const api = sync.require("../../matrix/api")
@ -21,4 +21,22 @@ async function deleteMessage(data) {
} }
} }
/**
* @param {import("discord-api-types/v10").GatewayMessageDeleteBulkDispatchData} data
*/
async function deleteMessageBulk(data) {
const roomID = select("channel_room", "room_id", {channel_id: data.channel_id}).pluck().get()
if (!roomID) return
const sids = JSON.stringify(data.ids)
const eventsToRedact = from("event_message").pluck("event_id").and("WHERE message_id IN (SELECT value FROM json_each(?)").all(sids)
db.prepare("DELETE FROM message_channel WHERE message_id IN (SELECT value FROM json_each(?)").run(sids)
db.prepare("DELETE FROM event_message WHERE message_id IN (SELECT value FROM json_each(?)").run(sids)
for (const eventID of eventsToRedact) {
// Awaiting will make it go slower, but since this could be a long-running operation either way, we want to leave rate limit capacity for other operations
await api.redactEvent(roomID, eventID)
}
}
module.exports.deleteMessage = deleteMessage module.exports.deleteMessage = deleteMessage
module.exports.deleteMessageBulk = deleteMessageBulk

View file

@ -153,6 +153,9 @@ const utils = {
} else if (message.t === "MESSAGE_DELETE") { } else if (message.t === "MESSAGE_DELETE") {
await eventDispatcher.onMessageDelete(client, message.d) 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") { } else if (message.t === "TYPING_START") {
await eventDispatcher.onTypingStart(client, message.d) await eventDispatcher.onTypingStart(client, message.d)

View file

@ -1,3 +1,5 @@
// @ts-check
const assert = require("assert").strict const assert = require("assert").strict
const DiscordTypes = require("discord-api-types/v10") const DiscordTypes = require("discord-api-types/v10")
const util = require("util") const util = require("util")
@ -47,27 +49,33 @@ module.exports = {
if (Date.now() - lastReportedEvent < 5000) return if (Date.now() - lastReportedEvent < 5000) return
lastReportedEvent = Date.now() lastReportedEvent = Date.now()
const channelID = gatewayMessage.d.channel_id const channelID = gatewayMessage.d["channel_id"]
if (!channelID) return if (!channelID) return
const roomID = select("channel_room", "room_id", {channel_id: channelID}).pluck().get() const roomID = select("channel_room", "room_id", {channel_id: channelID}).pluck().get()
if (!roomID) return if (!roomID) return
let stackLines = e.stack.split("\n") let stackLines = null
if (e.stack) {
stackLines = e.stack.split("\n")
let cloudstormLine = stackLines.findIndex(l => l.includes("/node_modules/cloudstorm/")) let cloudstormLine = stackLines.findIndex(l => l.includes("/node_modules/cloudstorm/"))
if (cloudstormLine !== -1) { if (cloudstormLine !== -1) {
stackLines = stackLines.slice(0, cloudstormLine - 2) stackLines = stackLines.slice(0, cloudstormLine - 2)
} }
}
let formattedBody = "\u26a0 <strong>Bridged event from Discord not delivered</strong>"
+ `<br>Gateway event: ${gatewayMessage.t}`
+ `<br>${e.toString()}`
if (stackLines) {
formattedBody += `<br><details><summary>Error trace</summary>`
+ `<pre>${stackLines.join("\n")}</pre></details>`
}
formattedBody += `<details><summary>Original payload</summary>`
+ `<pre>${util.inspect(gatewayMessage.d, false, 4, false)}</pre></details>`,
api.sendEvent(roomID, "m.room.message", { api.sendEvent(roomID, "m.room.message", {
msgtype: "m.text", msgtype: "m.text",
body: "\u26a0 Bridged event from Discord not delivered. See formatted content for full details.", body: "\u26a0 Bridged event from Discord not delivered. See formatted content for full details.",
format: "org.matrix.custom.html", format: "org.matrix.custom.html",
formatted_body: "\u26a0 <strong>Bridged event from Discord not delivered</strong>" formatted_body: formattedBody,
+ `<br>Gateway event: ${gatewayMessage.t}`
+ `<br>${e.toString()}`
+ `<br><details><summary>Error trace</summary>`
+ `<pre>${stackLines.join("\n")}</pre></details>`
+ `<details><summary>Original payload</summary>`
+ `<pre>${util.inspect(gatewayMessage.d, false, 4, false)}</pre></details>`,
"moe.cadence.ooye.error": { "moe.cadence.ooye.error": {
source: "discord", source: "discord",
payload: gatewayMessage payload: gatewayMessage
@ -91,7 +99,7 @@ module.exports = {
const prepared = select("event_message", "event_id", {}, "WHERE message_id = ?").pluck() const prepared = select("event_message", "event_id", {}, "WHERE message_id = ?").pluck()
for (const channel of guild.channels.concat(guild.threads)) { for (const channel of guild.channels.concat(guild.threads)) {
if (!bridgedChannels.includes(channel.id)) continue if (!bridgedChannels.includes(channel.id)) continue
if (!channel.last_message_id) continue if (!("last_message_id" in channel) || !channel.last_message_id) continue
const latestWasBridged = prepared.get(channel.last_message_id) const latestWasBridged = prepared.get(channel.last_message_id)
if (latestWasBridged) continue if (latestWasBridged) continue
@ -116,7 +124,6 @@ module.exports = {
for (let i = Math.min(messages.length, latestBridgedMessageIndex)-1; i >= 0; i--) { for (let i = Math.min(messages.length, latestBridgedMessageIndex)-1; i >= 0; i--) {
const simulatedGatewayDispatchData = { const simulatedGatewayDispatchData = {
guild_id: guild.id, guild_id: guild.id,
mentions: [],
backfill: true, backfill: true,
...messages[i] ...messages[i]
} }
@ -127,7 +134,6 @@ module.exports = {
/** /**
* When logging back in, check if we missed any changes to emojis or stickers. Apply the changes if so. * When logging back in, check if we missed any changes to emojis or stickers. Apply the changes if so.
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayGuildCreateDispatchData} guild * @param {DiscordTypes.GatewayGuildCreateDispatchData} guild
*/ */
async checkMissedExpressions(guild) { async checkMissedExpressions(guild) {
@ -142,7 +148,8 @@ module.exports = {
* @param {DiscordTypes.APIThreadChannel} thread * @param {DiscordTypes.APIThreadChannel} thread
*/ */
async onThreadCreate(client, thread) { async onThreadCreate(client, thread) {
const parentRoomID = select("channel_room", "room_id", {channel_id: thread.parent_id}).pluck().get() 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 if (!parentRoomID) return // Not interested in a thread if we aren't interested in its wider channel
const threadRoomID = await createRoom.syncRoom(thread.id) // Create room (will share the same inflight as the initial message to the thread) const threadRoomID = await createRoom.syncRoom(thread.id) // Create room (will share the same inflight as the initial message to the thread)
await announceThread.announceThread(parentRoomID, threadRoomID, thread) await announceThread.announceThread(parentRoomID, threadRoomID, thread)
@ -192,10 +199,10 @@ module.exports = {
return return
} }
} }
/** @type {DiscordTypes.APIGuildChannel} */
const channel = client.channels.get(message.channel_id) const channel = client.channels.get(message.channel_id)
if (!channel.guild_id) return // Nothing we can do in direct messages. if (!channel || !("guild_id" in channel) || !channel.guild_id) return // Nothing we can do in direct messages.
const guild = client.guilds.get(channel.guild_id) const guild = client.guilds.get(channel.guild_id)
assert(guild)
await sendMessage.sendMessage(message, guild), await sendMessage.sendMessage(message, guild),
await discordCommandHandler.execute(message, channel, guild) await discordCommandHandler.execute(message, channel, guild)
@ -217,11 +224,12 @@ module.exports = {
// If the message content is a string then it includes all interesting fields and is meaningful. // If the message content is a string then it includes all interesting fields and is meaningful.
if (typeof data.content === "string") { if (typeof data.content === "string") {
/** @type {DiscordTypes.GatewayMessageCreateDispatchData} */ /** @type {DiscordTypes.GatewayMessageCreateDispatchData} */
// @ts-ignore
const message = data const message = data
/** @type {DiscordTypes.APIGuildChannel} */
const channel = client.channels.get(message.channel_id) const channel = client.channels.get(message.channel_id)
if (!channel.guild_id) return // Nothing we can do in direct messages. if (!channel || !("guild_id" in channel) || !channel.guild_id) return // Nothing we can do in direct messages.
const guild = client.guilds.get(channel.guild_id) const guild = client.guilds.get(channel.guild_id)
assert(guild)
await editMessage.editMessage(message, guild) await editMessage.editMessage(message, guild)
} }
}, },
@ -254,6 +262,14 @@ module.exports = {
/** /**
* @param {import("./discord-client")} client * @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayMessageDeleteBulkDispatchData} data
*/
async onMessageDeleteBulk(client, data) {
await deleteMessage.deleteMessageBulk(data)
},
/**
* @param {import("./discord-client")} client
* @param {DiscordTypes.GatewayTypingStartDispatchData} data * @param {DiscordTypes.GatewayTypingStartDispatchData} data
*/ */
async onTypingStart(client, data) { async onTypingStart(client, data) {