Compare commits

..

2 commits

Author SHA1 Message Date
Bea
e382d67feb
feat: make sims leave rooms when Discord user leaves guild
Listen for GUILD_MEMBER_REMOVE events to remove sim users from
bridged Matrix rooms when their corresponding Discord user leaves
(or is kicked/banned from) the guild. Also removes PluralKit proxy
sims owned by the departing user.

Includes a backfill check on GUILD_CREATE to clean up sims for
users who left while the bridge was offline.

Closes #58
2026-03-08 23:14:12 +00:00
Bea
3042db36ca
feat(backfill): auto-create bridged rooms if they don't exist 2026-03-08 23:14:12 +00:00

View file

@ -10,6 +10,7 @@ if (!channelID) {
process.exit(1) process.exit(1)
} }
const assert = require("assert/strict")
const sqlite = require("better-sqlite3") const sqlite = require("better-sqlite3")
const backfill = new sqlite("scripts/backfill.db") const backfill = new sqlite("scripts/backfill.db")
backfill.prepare("CREATE TABLE IF NOT EXISTS backfill (channel_id TEXT NOT NULL, message_id INTEGER NOT NULL, PRIMARY KEY (channel_id, message_id))").run() backfill.prepare("CREATE TABLE IF NOT EXISTS backfill (channel_id TEXT NOT NULL, message_id INTEGER NOT NULL, PRIMARY KEY (channel_id, message_id))").run()
@ -55,29 +56,35 @@ async function event(event) {
if (!channel) return if (!channel) return
const guild_id = event.d.id const guild_id = event.d.id
try { let roomID = passthrough.select("channel_room", "room_id", {channel_id: channelID}).pluck().get()
await createRoom.syncRoom(channelID) if (!roomID) {
let last = backfill.prepare("SELECT cast(max(message_id) as TEXT) FROM backfill WHERE channel_id = ?").pluck().get(channelID) || "0" console.log(`Channel #${channel.name} is not bridged yet. Attempting to auto-create...`)
console.log(`OK, processing messages for #${channel.name}, continuing from ${last}`) try {
roomID = await createRoom.syncRoom(channelID)
while (last) { console.log(`Successfully bridged to new room: ${roomID}`)
const messages = await discord.snow.channel.getChannelMessages(channelID, {limit: 50, after: String(last)}) } catch (e) {
messages.reverse() // More recent messages come first -> More recent messages come last console.error(`Failed to auto-create room: ${e.message}`)
for (const message of messages) { process.exit(1)
const simulatedGatewayDispatchData = {
guild_id,
backfill: true,
...message
}
await eventDispatcher.MESSAGE_CREATE(discord, simulatedGatewayDispatchData)
preparedInsert.run(channelID, message.id)
}
last = messages.at(-1)?.id
} }
process.exit()
} catch (e) {
console.error(e)
process.exit(1) // won't exit automatically on thrown error due to living discord connection, so manual exit is necessary
} }
let last = backfill.prepare("SELECT cast(max(message_id) as TEXT) FROM backfill WHERE channel_id = ?").pluck().get(channelID) || "0"
console.log(`OK, processing messages for #${channel.name}, continuing from ${last}`)
while (last) {
const messages = await discord.snow.channel.getChannelMessages(channelID, {limit: 50, after: String(last)})
messages.reverse() // More recent messages come first -> More recent messages come last
for (const message of messages) {
const simulatedGatewayDispatchData = {
guild_id,
backfill: true,
...message
}
await eventDispatcher.MESSAGE_CREATE(discord, simulatedGatewayDispatchData)
preparedInsert.run(channelID, message.id)
}
last = messages.at(-1)?.id
}
process.exit()
} }