diff --git a/docs/get-started.md b/docs/get-started.md
index 17c98de..5b14b2a 100644
--- a/docs/get-started.md
+++ b/docs/get-started.md
@@ -56,16 +56,8 @@ After that, to get into the rooms on your Matrix account, use the invite form on
I hope you enjoy Out Of Your Element!
-# Extras
-
-## /plu/ral support
-
-To support /plu/ral webhook proxying, OOYE needs to call the /plu/ral API authenticated. I can't provide an API key for everyone to share, so you have to make your own. Here's how:
-
-1. Open the [/plu/ral app on Discord](https://discord.com/discovery/applications/1291501048493768784) and "Add App" -> "Add to My Apps (use everywhere)"
-2. Go to any text channel on Discord and use the new `/api` command from /plu/ral.
-3. Create a new application named Out Of Your Element. Copy the displayed token.
-3. Run `node scripts/plu-ral-api.js` and paste the token.
+----
+
# Appendix
diff --git a/scripts/plu-ral-api.js b/scripts/plu-ral-api.js
deleted file mode 100644
index d3468a3..0000000
--- a/scripts/plu-ral-api.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// @ts-check
-
-const {reg, writeRegistration} = require("../src/matrix/read-registration")
-const {prompt} = require("enquirer")
-
-;(async () => {
- /** @type {{api_key: string}} */
- const apiKeyResponse = await prompt({
- type: "text",
- name: "api_key",
- message: "Paste your personal /plu/ral API key"
- })
-
- reg.ooye.plu_ral_api_key = apiKeyResponse.api_key
- writeRegistration(reg)
- console.log("Saved. This change should be applied instantly.")
-})()
diff --git a/src/d2m/actions/edit-message.js b/src/d2m/actions/edit-message.js
index 31f3627..f86a9c8 100644
--- a/src/d2m/actions/edit-message.js
+++ b/src/d2m/actions/edit-message.js
@@ -1,24 +1,24 @@
// @ts-check
+const assert = require("assert").strict
+
const passthrough = require("../../passthrough")
const {sync, db, select, from} = passthrough
-const {reg} = require("../../matrix/read-registration")
/** @type {import("../converters/edit-to-changes")} */
const editToChanges = sync.require("../converters/edit-to-changes")
-/** @type {import("./speedbump")} */
-const speedbump = sync.require("./speedbump")
+/** @type {import("./register-pk-user")} */
+const registerPkUser = sync.require("./register-pk-user")
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
/** @type {import("../../matrix/mreq")} */
const mreq = sync.require("../../matrix/mreq")
-/** @type {import("../../discord/utils")} */
-const dUtils = sync.require("../../discord/utils")
/**
* @param {import("discord-api-types/v10").GatewayMessageCreateDispatchData} message
* @param {import("discord-api-types/v10").APIGuild} guild
+ * @param {{speedbump_id: string, speedbump_webhook_id: string} | null} row data about the webhook which is proxying messages in this channel
*/
-async function editMessage(message, guild) {
+async function editMessage(message, guild, row) {
const historicalRoomOfMessage = from("message_room").join("historical_channel_room", "historical_room_index").where({message_id: message.id}).select("room_id").get()
const currentRoom = from("channel_room").join("historical_channel_room", "room_id").where({channel_id: message.channel_id}).select("room_id", "historical_room_index").get()
if (!currentRoom) return
@@ -27,9 +27,11 @@ async function editMessage(message, guild) {
let {roomID, eventsToRedact, eventsToReplace, eventsToSend, senderMxid, promotions} = await editToChanges.editToChanges(message, guild, api)
- // Sync proxy user profile (if sent by proxy)
- if (dUtils.isWebhookMessage(message)) {
- senderMxid = await speedbump.getWebhookSenderId(message, guild.id, roomID)
+ if (row && row.speedbump_webhook_id === message.webhook_id) {
+ // Handle the PluralKit public instance
+ if (row.speedbump_id === "466378653216014359") {
+ senderMxid = await registerPkUser.syncUser(message.id, message.author, roomID, true)
+ }
}
// 1. Replace all the things.
diff --git a/src/d2m/actions/register-pk-user.js b/src/d2m/actions/register-pk-user.js
index 4946d4f..6ecd077 100644
--- a/src/d2m/actions/register-pk-user.js
+++ b/src/d2m/actions/register-pk-user.js
@@ -1,6 +1,6 @@
// @ts-check
-const assert = require("assert").strict
+const assert = require("assert")
const {reg} = require("../../matrix/read-registration")
const Ty = require("../../types")
@@ -132,10 +132,10 @@ async function syncUser(messageID, author, roomID, shouldActuallySync) {
try {
// API lookup
var pkMessage = await fetchMessage(messageID)
- db.prepare("REPLACE INTO sim_proxy (user_id, proxy_owner_id, displayname, proxy_app) VALUES (?, ?, ?, 0)").run(pkMessage.member.uuid, pkMessage.sender, author.username)
+ db.prepare("REPLACE INTO sim_proxy (user_id, proxy_owner_id, displayname) VALUES (?, ?, ?)").run(pkMessage.member.uuid, pkMessage.sender, author.username)
} catch (e) {
// Fall back to offline cache
- const senderMxid = from("sim_proxy").join("sim", "user_id").join("sim_member", "mxid").where({displayname: author.username, room_id: roomID, proxy_app: 0}).pluck("mxid").get()
+ const senderMxid = from("sim_proxy").join("sim", "user_id").join("sim_member", "mxid").where({displayname: author.username, room_id: roomID}).pluck("mxid").get()
if (!senderMxid) throw e
return senderMxid
}
diff --git a/src/d2m/actions/register-plu-ral-user.js b/src/d2m/actions/register-plu-ral-user.js
deleted file mode 100644
index 04fa28c..0000000
--- a/src/d2m/actions/register-plu-ral-user.js
+++ /dev/null
@@ -1,170 +0,0 @@
-// @ts-check
-
-const assert = require("assert").strict
-const {reg} = require("../../matrix/read-registration")
-const Ty = require("../../types")
-
-const passthrough = require("../../passthrough")
-const {sync, db, select, from} = passthrough
-/** @type {import("../../matrix/api")} */
-const api = sync.require("../../matrix/api")
-/** @type {import("../../matrix/file")} */
-const file = sync.require("../../matrix/file")
-/** @type {import("./register-user")} */
-const registerUser = sync.require("./register-user")
-
-/** @returns {Promise} */
-async function fetchMessage(channelID, messageID) {
- assert(reg.ooye.plu_ral_api_key)
- try {
- var res = await fetch(`https://api.plural.gg/messages/${channelID}/${messageID}?member=true`, {
- headers: {
- Authorization: reg.ooye.plu_ral_api_key
- }
- })
- } catch (networkError) {
- // Network issue, raise a more readable message
- throw new Error(`Failed to connect to /plu/ral API: ${networkError.toString()}`)
- }
- if (!res.ok) throw new Error(`/plu/ral API returned an error: ${await res.text()}`)
- /** @type {any} */
- const root = await res.json()
- if (!root.member) throw new Error(`/plu/ral API didn't return member data: ${JSON.stringify(root)}`)
- return root
-}
-
-/**
- * Using the same sim names and fake user IDs for /plu/ral members, since unlike PluralKit they don't have a short and a long ID.
- * @param {Ty.PluRalWebhookMessage} pluRalMessage
- */
-function getSimName(pluRalMessage) {
- return `_pl_${pluRalMessage.member_id}`
-}
-
-/**
- * A sim is an account that is being simulated by the bridge to copy events from the other side.
- * @param {Ty.PluRalWebhookMessage} pluRalMessage
- * @returns mxid
- */
-async function createSim(pluRalMessage) {
- // Choose sim name
- const simName = getSimName(pluRalMessage)
- const localpart = reg.ooye.namespace_prefix + simName
- const mxid = `@${localpart}:${reg.ooye.server_name}`
-
- // Save chosen name in the database forever
- db.prepare("INSERT INTO sim (user_id, username, sim_name, mxid) VALUES (?, ?, ?, ?)").run(simName, simName, simName, mxid)
-
- // Register matrix user with that name
- try {
- await api.register(localpart)
- } catch (e) {
- // If user creation fails, manually undo the database change. Still isn't perfect, but should help.
- // (I would prefer a transaction, but it's not safe to leave transactions open across event loop ticks.)
- db.prepare("DELETE FROM sim WHERE user_id = ?").run(simName)
- throw e
- }
- return mxid
-}
-
-/**
- * Ensure a sim is registered for the user.
- * If there is already a sim, use that one. If there isn't one yet, register a new sim.
- * @param {Ty.PluRalWebhookMessage} pluRalMessage
- * @returns {Promise} mxid
- */
-async function ensureSim(pluRalMessage) {
- let mxid = null
- const existing = select("sim", "mxid", {user_id: getSimName(pluRalMessage)}).pluck().get()
- if (existing) {
- mxid = existing
- } else {
- mxid = await createSim(pluRalMessage)
- }
- return mxid
-}
-
-/**
- * Ensure a sim is registered for the user and is joined to the room.
- * @param {Ty.PluRalWebhookMessage} pluRalMessage
- * @param {string} roomID
- * @returns {Promise} mxid
- */
-async function ensureSimJoined(pluRalMessage, roomID) {
- // Ensure room ID is really an ID, not an alias
- assert.ok(roomID[0] === "!")
-
- // Ensure user
- const mxid = await ensureSim(pluRalMessage)
-
- // Ensure joined
- const existing = select("sim_member", "mxid", {room_id: roomID, mxid}).pluck().get()
- if (!existing) {
- await api.inviteToRoom(roomID, mxid)
- await api.joinRoom(roomID, mxid)
- db.prepare("INSERT OR IGNORE INTO sim_member (room_id, mxid) VALUES (?, ?)").run(roomID, mxid)
- }
- return mxid
-}
-
-/**
- * Generate profile data based on webhook displayname and configured avatar.
- * @param {Ty.PluRalWebhookMessage} pluRalMessage
- * @param {Ty.WebhookAuthor} author
- */
-async function memberToStateContent(pluRalMessage, author) {
- // We prefer to use the member's avatar URL data since the image upload can be cached across channels,
- // unlike the userAvatar URL which is unique per channel, due to the webhook ID being in the URL.
- const avatar = pluRalMessage.member.avatar_url || file.userAvatar(author)
-
- const content = {
- displayname: author.username,
- membership: "join",
- "moe.cadence.ooye.plu_ral_member": pluRalMessage.member
- }
- if (avatar) content.avatar_url = await file.uploadDiscordFileToMxc(avatar)
-
- return content
-}
-
-/**
- * Sync profile data for a sim user. This function follows the following process:
- * 1. Look up data about proxy user from API
- * 2. If this fails, try to use previously cached data (won't sync)
- * 3. Create and join the sim to the room if needed
- * 4. Make an object of what the new room member state content would be, including uploading the profile picture if it hasn't been done before
- * 5. Compare against the previously known state content, which is helpfully stored in the database
- * 6. If the state content has changed, send it to Matrix and update it in the database for next time
- * @param {string} channelID to call API with
- * @param {string} messageID to call API with
- * @param {Ty.WebhookAuthor} author for profile data
- * @param {string} roomID room to join member to
- * @param {boolean} shouldActuallySync whether to actually sync updated user data or just ensure it's joined
- * @returns {Promise} mxid of the updated sim
- */
-async function syncUser(channelID, messageID, author, roomID, shouldActuallySync) {
- try {
- // API lookup
- var pluRalMessage = await fetchMessage(channelID, messageID)
- const simName = getSimName(pluRalMessage)
- db.prepare("REPLACE INTO sim_proxy (user_id, proxy_owner_id, displayname, proxy_app) VALUES (?, ?, ?, 1)").run(simName, pluRalMessage.author_id, author.username)
- } catch (e) {
- // Fall back to offline cache
- const senderMxid = from("sim_proxy").join("sim", "user_id").join("sim_member", "mxid").where({displayname: author.username, room_id: roomID, proxy_app: 1}).pluck("mxid").get()
- if (!senderMxid) throw e
- return senderMxid
- }
-
- // Create and join the sim to the room if needed
- const mxid = await ensureSimJoined(pluRalMessage, roomID)
-
- if (shouldActuallySync) {
- // Build current profile data and sync if the hash has changed
- const content = await memberToStateContent(pluRalMessage, author)
- await registerUser._sendSyncUser(roomID, mxid, content, null)
- }
-
- return mxid
-}
-
-module.exports.syncUser = syncUser
diff --git a/src/d2m/actions/send-message.js b/src/d2m/actions/send-message.js
index 41ef70d..5b3b4f3 100644
--- a/src/d2m/actions/send-message.js
+++ b/src/d2m/actions/send-message.js
@@ -4,16 +4,17 @@ const assert = require("assert").strict
const DiscordTypes = require("discord-api-types/v10")
const passthrough = require("../../passthrough")
-const {discord, sync, db, select, from} = passthrough
-const {reg} = require("../../matrix/read-registration")
+const { discord, sync, db, select, from} = passthrough
/** @type {import("../converters/message-to-event")} */
const messageToEvent = sync.require("../converters/message-to-event")
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
/** @type {import("./register-user")} */
const registerUser = sync.require("./register-user")
-/** @type {import("./speedbump")} */
-const speedbump = sync.require("./speedbump")
+/** @type {import("./register-pk-user")} */
+const registerPkUser = sync.require("./register-pk-user")
+/** @type {import("./register-webhook-user")} */
+const registerWebhookUser = sync.require("./register-webhook-user")
/** @type {import("../actions/create-room")} */
const createRoom = sync.require("../actions/create-room")
/** @type {import("../actions/poll-end")} */
@@ -27,15 +28,24 @@ const channelWebhook = sync.require("../../m2d/actions/channel-webhook")
* @param {DiscordTypes.GatewayMessageCreateDispatchData} message
* @param {DiscordTypes.APIGuildChannel} channel
* @param {DiscordTypes.APIGuild} guild
+ * @param {{speedbump_id: string, speedbump_webhook_id: string} | null} row data about the webhook which is proxying messages in this channel
*/
-async function sendMessage(message, channel, guild) {
+async function sendMessage(message, channel, guild, row) {
const roomID = await createRoom.ensureRoom(message.channel_id)
const historicalRoomIndex = select("historical_channel_room", "historical_room_index", {room_id: roomID}).pluck().get()
assert(historicalRoomIndex)
let senderMxid = null
if (dUtils.isWebhookMessage(message)) {
- senderMxid = await speedbump.getWebhookSenderId(message, guild.id, roomID)
+ const useWebhookProfile = select("guild_space", "webhook_profile", {guild_id: guild.id}).pluck().get() ?? 0
+ if (row && row.speedbump_webhook_id === message.webhook_id) {
+ // Handle the PluralKit public instance
+ if (row.speedbump_id === "466378653216014359") {
+ senderMxid = await registerPkUser.syncUser(message.id, message.author, roomID, true)
+ }
+ } else if (useWebhookProfile) {
+ senderMxid = await registerWebhookUser.syncUser(message.author, roomID, true)
+ }
} else {
// not a webhook
if (message.author.id === discord.application.id) {
diff --git a/src/d2m/actions/speedbump.js b/src/d2m/actions/speedbump.js
index 88cea07..42e3a35 100644
--- a/src/d2m/actions/speedbump.js
+++ b/src/d2m/actions/speedbump.js
@@ -1,23 +1,13 @@
// @ts-check
-const DiscordTypes = require("discord-api-types/v10")
-
const passthrough = require("../../passthrough")
-const {discord, from, select, db, sync} = passthrough
-
-const {reg} = require("../../matrix/read-registration")
-/** @type {import("./register-pk-user")} */
-const registerPkUser = sync.require("./register-pk-user")
-/** @type {import("./register-plu-ral-user")} */
-const registerPluRalUser = sync.require("./register-plu-ral-user")
-/** @type {import("./register-webhook-user")} */
-const registerWebhookUser = sync.require("./register-webhook-user")
+const {discord, select, db} = passthrough
const DEBUG_SPEEDBUMP = false
-function debugSpeedbump(...args) {
+function debugSpeedbump(message) {
if (DEBUG_SPEEDBUMP) {
- console.log(...args)
+ console.log(message)
}
}
@@ -26,8 +16,7 @@ const SPEEDBUMP_UPDATE_FREQUENCY = 2 * 60 * 60 // 2 hours
/** @type {Set} */
const KNOWN_BOTS = new Set([
- "466378653216014359", // PluralKit
- "1291501048493768784", // /plu/ral
+ "466378653216014359" // PluralKit
])
/**
@@ -39,81 +28,61 @@ async function updateCache(channelID, lastChecked) {
const now = Math.floor(Date.now() / 1000)
if (lastChecked && now - lastChecked < SPEEDBUMP_UPDATE_FREQUENCY) return
const webhooks = await discord.snow.webhook.getChannelWebhooks(channelID)
- const found = webhooks.filter(b => KNOWN_BOTS.has(b.application_id))
- db.transaction(() => {
- db.prepare("DELETE FROM channel_speedbump WHERE channel_id = ?").run(channelID)
- for (const webhook of found) {
- db.prepare("INSERT INTO channel_speedbump (channel_id, speedbump_webhook_id, speedbump_user_id) VALUES (?, ?, ?)").run(channelID, webhook.id, webhook.application_id)
- }
- db.prepare("UPDATE channel_room SET speedbump_checked = ? WHERE channel_id = ?").run(now, channelID)
- })()
+ const found = webhooks.find(b => KNOWN_BOTS.has(b.application_id))
+ const foundApplication = found?.application_id
+ const foundWebhook = found?.id
+ db.prepare("UPDATE channel_room SET speedbump_id = ?, speedbump_webhook_id = ?, speedbump_checked = ? WHERE channel_id = ?").run(foundApplication, foundWebhook, now, channelID)
}
-/**
- * @typedef BumpingEntry
- * @prop {number} number number of gateway events currently bumping for this message ID
- * @prop {boolean} hasCreate whether there was a message create within the events currently bumping
- */
-
-/** @type {Map} messageID -> BumpingEntry */
+/** @type {Map} messageID -> number of gateway events currently bumping */
const bumping = new Map()
/**
* Slow down a message. After it passes the speedbump, return whether it's okay or if it's been deleted.
- * @param {boolean} isCreate
* @param {string} messageID
* @returns whether it was deleted
*/
-async function doSpeedbump(isCreate, messageID) {
- const entry = bumping.get(messageID) ?? (() => {
- const entry = {number: 0, hasCreate: false}
- bumping.set(messageID, entry)
- return entry
- })()
-
- entry.number++
- entry.hasCreate ||= isCreate
-
- debugSpeedbump(`[speedbump] WAIT ${messageID}++ =`, entry)
+async function doSpeedbump(messageID) {
+ let value = (bumping.get(messageID) ?? 0) + 1
+ bumping.set(messageID, value)
+ debugSpeedbump(`[speedbump] WAIT ${messageID}++ = ${value}`)
await new Promise(resolve => setTimeout(resolve, SPEEDBUMP_SPEED))
if (!bumping.has(messageID)) {
debugSpeedbump(`[speedbump] DELETED ${messageID}`)
- return {skip: true, hasCreate: null}
+ return true
}
-
- if (--entry.number <= 0) {
- debugSpeedbump(`[speedbump] OK ${messageID}-- =`, entry)
+ value = (bumping.get(messageID) ?? 0) - 1
+ if (value <= 0) {
+ debugSpeedbump(`[speedbump] OK ${messageID}-- = ${value}`)
bumping.delete(messageID)
- return {skip: false, hasCreate: entry.hasCreate}
+ return false
} else {
- debugSpeedbump(`[speedbump] MULTI ${messageID}-- =`, entry)
- return {skip: true, hasCreate: null}
+ debugSpeedbump(`[speedbump] MULTI ${messageID}-- = ${value}`)
+ bumping.set(messageID, value)
+ return true
}
}
-function getSpeedbumpRows(channelID) {
- return from("channel_room").join("channel_speedbump", "channel_id").select("thread_parent", "speedbump_user_id", "speedbump_webhook_id").where({channel_id: channelID}).all()
-}
-
/**
* Check whether to slow down a message, and do it. After it passes the speedbump, return whether it's okay or if it's been deleted.
- * @param {boolean} isCreate
- * @param {{id: string, channel_id: string, author: {id: string}, backfill?: boolean}} message uses the ID to identify, and the userID to only slow down the message when the user has used PK before
- * @returns whether to skip this message, and whether the message should be created as a creation
+ * @param {string} channelID
+ * @param {string} messageID
+ * @param {string} [userID] if provided, only slow down the message when the user has used PK before
+ * @returns whether it was deleted, and data about the channel's (not thread's) speedbump
*/
-async function maybeDoSpeedbump(isCreate, message) {
- let rows = getSpeedbumpRows(message.channel_id)
- if (rows[0]?.thread_parent) rows = getSpeedbumpRows(rows[0].thread_parent) // webhooks belong to the channel, not the thread
- if (!rows.length) return {skip: false} // channel not affected, no speedbump
-
- if (message.backfill) return {skip: false} // don't slow messages during backfill
- if (rows.some(r => r.speedbump_webhook_id === message.author.id)) return {skip: false} // shortcut
- const userHasProxy = select("sim_proxy", "user_id", {proxy_owner_id: message.author.id}).pluck().get()
- if (!userHasProxy) return {skip: false} // user has not used PK before, no speedbump
- const {skip, hasCreate} = await doSpeedbump(isCreate, message.id)
- return {skip, hasCreate} // maybe affected, and there is a speedbump
+async function maybeDoSpeedbump(channelID, messageID, userID) {
+ let row = select("channel_room", ["room_id", "thread_parent", "speedbump_id", "speedbump_webhook_id"], {channel_id: channelID}).get()
+ if (row?.thread_parent) row = select("channel_room", ["room_id", "thread_parent", "speedbump_id", "speedbump_webhook_id"], {channel_id: row.thread_parent}).get() // webhooks belong to the channel, not the thread
+ if (!row?.speedbump_webhook_id) return {affected: false, row: null} // channel not affected, no speedbump
+ if (userID) {
+ if (row.speedbump_webhook_id === userID) return {affected: false, row} // shortcut
+ const userHasProxy = select("sim_proxy", "user_id", {proxy_owner_id: userID}).pluck().get()
+ if (!userHasProxy) return {affected: false, row} // user has not used PK before, no speedbump
+ }
+ const affected = await doSpeedbump(messageID)
+ return {affected, row} // maybe affected, and there is a speedbump
}
/**
@@ -123,25 +92,7 @@ function onMessageDelete(messageID) {
bumping.delete(messageID)
}
-/**
- * @param {DiscordTypes.APIMessage} message
- * @param {string} guildID
- * @param {string} roomID
- */
-async function getWebhookSenderId(message, guildID, roomID) {
- const speedbumpUserID = select("channel_speedbump", "speedbump_user_id", {channel_id: message.channel_id, speedbump_webhook_id: message.webhook_id}).pluck().get()
- const useWebhookProfile = select("guild_space", "webhook_profile", {guild_id: guildID}).pluck().get() ?? 0
- if (speedbumpUserID === "466378653216014359") { // PluralKit public instance
- return await registerPkUser.syncUser(message.id, message.author, roomID, true)
- } else if (speedbumpUserID === "1291501048493768784" && reg.ooye.plu_ral_api_key) { // /plu/ral public instance
- return await registerPluRalUser.syncUser(message.channel_id, message.id, message.author, roomID, true)
- } else if (useWebhookProfile) {
- return await registerWebhookUser.syncUser(message.author, roomID, true)
- }
- return null
-}
-
module.exports.updateCache = updateCache
+module.exports.doSpeedbump = doSpeedbump
module.exports.maybeDoSpeedbump = maybeDoSpeedbump
module.exports.onMessageDelete = onMessageDelete
-module.exports.getWebhookSenderId = getWebhookSenderId
diff --git a/src/d2m/event-dispatcher.js b/src/d2m/event-dispatcher.js
index a49453a..c0c33d9 100644
--- a/src/d2m/event-dispatcher.js
+++ b/src/d2m/event-dispatcher.js
@@ -288,6 +288,7 @@ module.exports = {
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()
if (!roomID) return // channel wasn't being bridged in the first place
+ // @ts-ignore
await createRoom.unbridgeChannel(channel, guildID)
},
@@ -312,10 +313,11 @@ module.exports = {
if (!createRoom.existsOrAutocreatable(channel, guild.id)) return // Check that the sending-to room exists or is autocreatable
- const {skip} = await speedbump.maybeDoSpeedbump(true, message)
- if (skip) return
+ const {affected, row} = await speedbump.maybeDoSpeedbump(message.channel_id, message.id, message.author.id)
+ if (affected) return
- await sendMessage.sendMessage(message, channel, guild)
+ // @ts-ignore
+ await sendMessage.sendMessage(message, channel, guild, row)
retrigger.finishedBridging(message.id)
},
@@ -333,27 +335,22 @@ module.exports = {
if (dUtils.isEphemeralMessage(data)) return // Ephemeral messages are for the eyes of the receiver only!
// Edits need to go through the speedbump as well. If the message is delayed but the edit isn't, we don't have anything to edit from.
- const {skip, hasCreate} = await speedbump.maybeDoSpeedbump(false, data)
- if (skip) return
+ const {affected, row} = await speedbump.maybeDoSpeedbump(data.channel_id, data.id, data.author.id)
+ if (affected) return
+
+ // Check that the sending-to room exists, and deal with Eventual Consistency(TM)
+ if (!await retrigger.waitForMessage(data.id)) return
/** @type {DiscordTypes.GatewayMessageCreateDispatchData} */
+ // @ts-ignore
const message = data
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.
const guild = client.guilds.get(channel.guild_id)
assert(guild)
- if (!hasCreate) {
- // Standard path for most message updates
- // Check that the target message already exists, and deal with Eventual Consistency(TM)
- if (!await retrigger.waitForMessage(data.id)) return
- await retrigger.pauseChanges(message.id, editMessage.editMessage(message, guild))
- }
- else {
- // Path for edit packets that were speedbumped into the latest copy of a message that needs to be created
- // Just pretend to be MESSAGE_CREATE
- await sendMessage.sendMessage(message, channel, guild)
- }
+ // @ts-ignore
+ await retrigger.pauseChanges(message.id, editMessage.editMessage(message, guild, row))
},
/**
diff --git a/src/db/migrations/0039-refactor-speedbump.sql b/src/db/migrations/0039-refactor-speedbump.sql
deleted file mode 100644
index de739dc..0000000
--- a/src/db/migrations/0039-refactor-speedbump.sql
+++ /dev/null
@@ -1,19 +0,0 @@
-BEGIN TRANSACTION;
-
-CREATE TABLE "channel_speedbump" (
- "channel_id" TEXT NOT NULL,
- "speedbump_webhook_id" TEXT NOT NULL,
- "speedbump_user_id" TEXT NOT NULL,
- PRIMARY KEY("channel_id","speedbump_webhook_id"),
- FOREIGN KEY("channel_id") REFERENCES "channel_room"("channel_id")
-) WITHOUT ROWID;
-
-INSERT INTO channel_speedbump (channel_id, speedbump_webhook_id, speedbump_user_id)
- SELECT channel_id, speedbump_webhook_id, speedbump_id FROM channel_room WHERE speedbump_id IS NOT NULL AND speedbump_webhook_id IS NOT NULL;
-
-ALTER TABLE channel_room DROP COLUMN speedbump_id;
-ALTER TABLE channel_room DROP COLUMN speedbump_webhook_id;
-
-ALTER TABLE sim_proxy ADD COLUMN proxy_app INTEGER DEFAULT 0;
-
-COMMIT;
diff --git a/src/db/orm-defs.d.ts b/src/db/orm-defs.d.ts
index 14f320a..d95bfc3 100644
--- a/src/db/orm-defs.d.ts
+++ b/src/db/orm-defs.d.ts
@@ -18,17 +18,13 @@ export type Models = {
thread_parent: string | null
custom_avatar: string | null
last_bridged_pin_timestamp: number | null
+ speedbump_id: string | null
+ speedbump_webhook_id: string | null
speedbump_checked: number | null
guild_id: string | null
custom_topic: number
}
- channel_speedbump: {
- channel_id: string
- speedbump_webhook_id: string
- speedbump_user_id: string
- }
-
direct: {
mxid: string
room_id: string
@@ -48,7 +44,6 @@ export type Models = {
event_subtype: string | null
part: number
reaction_part: number
- /** 0 = Matrix, 1 = Discord */
source: number
}
@@ -142,8 +137,6 @@ export type Models = {
user_id: string
proxy_owner_id: string
displayname: string
- /** 0 = PluralKit, 1 = /plu/ral */
- proxy_app: number
}
webhook: {
diff --git a/src/matrix/mreq.js b/src/matrix/mreq.js
index b6bc5b9..bf238f2 100644
--- a/src/matrix/mreq.js
+++ b/src/matrix/mreq.js
@@ -9,10 +9,8 @@ const {reg} = require("./read-registration.js")
const baseUrl = `${reg.ooye.server_origin}/_matrix`
class MatrixServerError extends Error {
- /**
- * @param {number} httpStatus}
- */
- constructor(data, httpStatus, opts = {}) {
+ /** @param {number} httpStatus} */
+ constructor(data, httpStatus, opts) {
super(data.error || data.errcode)
this.data = data
/** @type {number} */
diff --git a/src/types.d.ts b/src/types.d.ts
index f65ce59..856ab1c 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -36,7 +36,6 @@ export type AppServiceRegistrationConfig = {
web_password: string
time_zone?: string
receive_presences: boolean
- plu_ral_api_key?: string
}
old_bridge?: {
as_token: string
@@ -125,28 +124,6 @@ export type PkMessage = {
sender: string
}
-export type PluRalWebhookMessage = {
- original_id: string | null
- proxy_id: string
- author_id: string
- channel_id: string
- member_id: string
- reason: string
- webhook_id: string
- member: PluRalMember
-}
-
-export type PluRalMember = {
- id: string
- name: string
- pronouns: string
- bio: string
- birthday: string
- color: number | null
- avatar_url: string
- private: boolean
-}
-
export namespace Event {
export type Outer = {
type: string
diff --git a/src/web/routes/link.test.js b/src/web/routes/link.test.js
index 32f89bf..0182093 100644
--- a/src/web/routes/link.test.js
+++ b/src/web/routes/link.test.js
@@ -73,7 +73,7 @@ test("web link space: check that OOYE is joined", async t => {
api: {
async joinRoom(roomID) {
called++
- throw new MatrixServerError({errcode: "M_FORBIDDEN", error: "not allowed to join I guess"}, 400)
+ throw new MatrixServerError({errcode: "M_FORBIDDEN", error: "not allowed to join I guess"})
}
}
}))
@@ -368,7 +368,7 @@ test("web link room: check that bridge can join room (notices lack of via and as
api: {
async joinRoom(roomID) {
called++
- throw new MatrixServerError({errcode: "M_FORBIDDEN", error: "not allowed to join I guess"}, 400)
+ throw new MatrixServerError({errcode: "M_FORBIDDEN", error: "not allowed to join I guess"})
},
async *generateFullHierarchy(spaceID) {
called++
@@ -402,7 +402,7 @@ test("web link room: check that bridge can join room (uses via for join attempt)
async joinRoom(roomID, _, via) {
called++
t.deepEqual(via, ["cadence.moe", "hashi.re"])
- throw new MatrixServerError({errcode: "M_FORBIDDEN", error: "not allowed to join I guess"}, 400)
+ throw new MatrixServerError({errcode: "M_FORBIDDEN", error: "not allowed to join I guess"})
},
async *generateFullHierarchy(spaceID) {
called++
@@ -710,7 +710,7 @@ test("web unlink room: checks that the channel is bridged", async t => {
}))
t.equal(error.data, "Channel ID 665310973967597573 is not currently bridged")
- db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_checked, guild_id, custom_topic) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(row.channel_id, row.room_id, row.name, row.nick, row.thread_parent, row.custom_avatar, row.last_bridged_pin_timestamp, row.speedbump_checked, row.guild_id, row.custom_topic)
+ db.prepare("INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom_avatar, last_bridged_pin_timestamp, speedbump_id, speedbump_checked, speedbump_webhook_id, guild_id, custom_topic) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(row.channel_id, row.room_id, row.name, row.nick, row.thread_parent, row.custom_avatar, row.last_bridged_pin_timestamp, row.speedbump_id, row.speedbump_checked, row.speedbump_webhook_id, row.guild_id, row.custom_topic)
const new_row = db.prepare("SELECT * FROM channel_room WHERE channel_id = '665310973967597573'").get()
t.deepEqual(row, new_row)
})