Implement the speedbump

This commit is contained in:
Cadence Ember 2024-01-20 01:01:34 +13:00
parent 5ef5dbb2e8
commit e49dc18e67
9 changed files with 90 additions and 13 deletions

View file

@ -4,21 +4,25 @@ const passthrough = require("../../passthrough")
const {sync, db, select, from} = passthrough
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
/** @type {import("./speedbump")} */
const speedbump = sync.require("./speedbump")
/**
* @param {import("discord-api-types/v10").GatewayMessageDeleteDispatchData} data
*/
async function deleteMessage(data) {
const roomID = select("channel_room", "room_id", {channel_id: data.channel_id}).pluck().get()
if (!roomID) return
const row = select("channel_room", ["room_id", "speedbump_id", "speedbump_checked"], {channel_id: data.channel_id}).get()
if (!row) return
const eventsToRedact = select("event_message", "event_id", {message_id: data.id}).pluck().all()
db.prepare("DELETE FROM message_channel WHERE message_id = ?").run(data.id)
db.prepare("DELETE FROM event_message WHERE message_id = ?").run(data.id)
for (const eventID of eventsToRedact) {
// Unfortunately, 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)
await api.redactEvent(row.room_id, eventID)
}
speedbump.updateCache(data.channel_id, row.speedbump_id, row.speedbump_checked)
}
/**

51
d2m/actions/speedbump.js Normal file
View file

@ -0,0 +1,51 @@
// @ts-check
const DiscordTypes = require("discord-api-types/v10")
const passthrough = require("../../passthrough")
const {discord, db} = passthrough
const SPEEDBUMP_SPEED = 4000 // 4 seconds delay
const SPEEDBUMP_UPDATE_FREQUENCY = 2 * 60 * 60 // 2 hours
/** @type {Set<any>} */
const KNOWN_BOTS = new Set([
"466378653216014359" // PluralKit
])
/**
* Fetch new speedbump data for the channel and put it in the database as cache
* @param {string} channelID
* @param {string?} speedbumpID
* @param {number?} speedbumpChecked
*/
async function updateCache(channelID, speedbumpID, speedbumpChecked) {
const now = Math.floor(Date.now() / 1000)
if (speedbumpChecked && now - speedbumpChecked < SPEEDBUMP_UPDATE_FREQUENCY) return
const webhooks = await discord.snow.webhook.getChannelWebhooks(channelID)
const found = webhooks.find(b => KNOWN_BOTS.has(b.application_id))?.application_id || null
db.prepare("UPDATE channel_room SET speedbump_id = ?, speedbump_checked = ? WHERE channel_id = ?").run(found, now, channelID)
}
/** @type {Set<string>} set of messageID */
const bumping = new Set()
/**
* Slow down a message. After it passes the speedbump, return whether it's okay or if it's been deleted.
* @param {string} messageID
*/
async function doSpeedbump(messageID) {
bumping.add(messageID)
await new Promise(resolve => setTimeout(resolve, SPEEDBUMP_SPEED))
return !bumping.delete(messageID)
}
/**
* @param {string} messageID
*/
function onMessageDelete(messageID) {
bumping.delete(messageID)
}
module.exports.updateCache = updateCache
module.exports.doSpeedbump = doSpeedbump
module.exports.onMessageDelete = onMessageDelete

View file

@ -47,7 +47,16 @@ class DiscordClient {
if (listen !== "no") {
this.cloud.on("event", message => discordPackets.onPacket(this, message, listen))
}
this.cloud.on("error", console.error)
const addEventLogger = (eventName, logName) => {
this.cloud.on(eventName, (...args) => {
const d = new Date().toISOString().slice(0, 19)
console.error(`[${d} Client ${logName}]`, ...args)
})
}
addEventLogger("error", "Error")
addEventLogger("disconnected", "Disconnected")
addEventLogger("ready", "Ready")
}
}

View file

@ -31,6 +31,8 @@ const dUtils = sync.require("../discord/utils")
const discordCommandHandler = sync.require("../discord/discord-command-handler")
/** @type {import("../m2d/converters/utils")} */
const mxUtils = require("../m2d/converters/utils")
/** @type {import("./actions/speedbump")} */
const speedbump = sync.require("./actions/speedbump")
/** @type {any} */ // @ts-ignore bad types from semaphore
const Semaphore = require("@chriscdn/promise-semaphore")
@ -236,9 +238,12 @@ module.exports = {
if (message.author.username === "Deleted User") return // Nothing we can do for deleted users.
if (message.webhook_id) {
const row = select("webhook", "webhook_id", {webhook_id: message.webhook_id}).pluck().get()
if (row) {
// The message was sent by the bridge's own webhook on discord. We don't want to reflect this back, so just drop it.
return
if (row) return // The message was sent by the bridge's own webhook on discord. We don't want to reflect this back, so just drop it.
} else {
const speedbumpID = select("channel_room", "speedbump_id", {channel_id: message.channel_id}).pluck().get()
if (speedbumpID) {
const affected = await speedbump.doSpeedbump(message.id)
if (affected) return
}
}
const channel = client.channels.get(message.channel_id)
@ -299,6 +304,7 @@ module.exports = {
* @param {DiscordTypes.GatewayMessageDeleteDispatchData} data
*/
async onMessageDelete(client, data) {
speedbump.onMessageDelete(data.id)
await deleteMessage.deleteMessage(data)
},