Compare commits

..

No commits in common. "c3040f19c2a1e4e0c16c0195062b89d1d3d3dafb" and "4f807159ba0b9a6765e0328f06c6efb2032b668a" have entirely different histories.

9 changed files with 38 additions and 81 deletions

View file

@ -10,9 +10,8 @@ const api = sync.require("../../matrix/api")
const registerUser = sync.require("./register-user")
/** @type {import("../actions/create-room")} */
const createRoom = sync.require("../actions/create-room")
/** @type {import("../converters/emoji-to-key")} */
const emojiToKey = sync.require("../converters/emoji-to-key")
/** @type {import("../../matrix/file")} */
const file = sync.require("../../matrix/file")
/**
* @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data
@ -25,8 +24,24 @@ async function addReaction(data) {
if (!parentID) return // Nothing can be done if the parent message was never bridged.
assert.equal(typeof parentID, "string")
const key = await emojiToKey.emojiToKey(data.emoji)
const shortcode = key.startsWith("mxc://") ? `:${data.emoji.name}:` : undefined
let key
if (data.emoji.id) {
// Custom emoji
const mxc = select("emoji", "mxc_url", "WHERE id = ?").pluck().get(data.emoji.id)
if (mxc) {
// The custom emoji is registered and we should send it
key = mxc
} else {
// The custom emoji is not registered. We will register it and then add it.
const mxc = await file.uploadDiscordFileToMxc(file.emoji(data.emoji.id, data.emoji.animated))
db.prepare("INSERT OR IGNORE INTO emoji (id, name, animated, mxc_url) VALUES (?, ?, ?, ?)").run(data.emoji.id, data.emoji.name, +!!data.emoji.animated, mxc)
key = mxc
// TODO: what happens if the matrix user also tries adding this reaction? the bridge bot isn't able to use that emoji...
}
} else {
// Default emoji
key = data.emoji.name
}
const roomID = await createRoom.ensureRoom(data.channel_id)
const senderMxid = await registerUser.ensureSimJoined(user, roomID)
@ -35,8 +50,7 @@ async function addReaction(data) {
rel_type: "m.annotation",
event_id: parentID,
key
},
shortcode
}
}, senderMxid)
return eventID
}

View file

@ -7,8 +7,12 @@ const passthrough = require("../../passthrough")
const {discord, sync, db, select} = passthrough
/** @type {import("../../matrix/api")} */
const api = sync.require("../../matrix/api")
/** @type {import("../converters/emoji-to-key")} */
const emojiToKey = sync.require("../converters/emoji-to-key")
/** @type {import("./register-user")} */
const registerUser = sync.require("./register-user")
/** @type {import("../actions/create-room")} */
const createRoom = sync.require("../actions/create-room")
/** @type {import("../../matrix/file")} */
const file = sync.require("../../matrix/file")
/**
* @param {import("discord-api-types/v10").GatewayMessageReactionRemoveDispatchData} data
@ -23,11 +27,10 @@ async function removeReaction(data) {
/** @type {Ty.Pagination<Ty.Event.Outer<Ty.Event.M_Reaction>>} */
const relations = await api.getRelations(roomID, eventIDForMessage, "m.annotation")
const key = await emojiToKey.emojiToKey(data.emoji)
const eventIDForReaction = relations.chunk.find(e => e.sender === mxid && e.content["m.relates_to"].key === key)
const eventIDForReaction = relations.chunk.find(e => e.sender === mxid && e.content["m.relates_to"].key === data.emoji) // TODO: get the key from the emoji
if (!eventIDForReaction) return
await api.redactEvent(roomID, eventIDForReaction.event_id, mxid)
await api.redactEvent(roomID, eventIDForReaction, mxid)
}
module.exports.removeReaction = removeReaction

View file

@ -1,38 +0,0 @@
// @ts-check
const assert = require("assert").strict
const passthrough = require("../../passthrough")
const {discord, sync, db, select} = passthrough
/** @type {import("../../matrix/file")} */
const file = sync.require("../../matrix/file")
/**
* @param {import("discord-api-types/v10").APIEmoji} emoji
* @returns {Promise<string>}
*/
async function emojiToKey(emoji) {
let key
if (emoji.id) {
// Custom emoji
const mxc = select("emoji", "mxc_url", "WHERE id = ?").pluck().get(emoji.id)
if (mxc) {
// The custom emoji is registered and we should send it
key = mxc
} else {
// The custom emoji is not registered. We will register it and then add it.
assert(emoji.name) // The docs say: "name may be null when custom emoji data is not available, for example, if it was deleted from the guild"
const mxc = await file.uploadDiscordFileToMxc(file.emoji(emoji.id, emoji.animated))
db.prepare("INSERT OR IGNORE INTO emoji (id, name, animated, mxc_url) VALUES (?, ?, ?, ?)").run(emoji.id, emoji.name, +!!emoji.animated, mxc)
key = mxc
// TODO: what happens if the matrix user also tries adding this reaction? the bridge bot isn't able to use that emoji...
}
} else {
// Default emoji
const name = emoji.name
assert(name)
key = name
}
return key
}
module.exports.emojiToKey = emojiToKey

View file

@ -155,9 +155,6 @@ const utils = {
} else if (message.t === "MESSAGE_REACTION_ADD") {
await eventDispatcher.onReactionAdd(client, message.d)
} else if (message.t === "MESSAGE_REACTION_REMOVE") {
await eventDispatcher.onReactionRemove(client, message.d)
}
} catch (e) {
// Let OOYE try to handle errors too

View file

@ -10,8 +10,6 @@ const editMessage = sync.require("./actions/edit-message")
const deleteMessage = sync.require("./actions/delete-message")
/** @type {import("./actions/add-reaction")}) */
const addReaction = sync.require("./actions/add-reaction")
/** @type {import("./actions/remove-reaction")}) */
const removeReaction = sync.require("./actions/remove-reaction")
/** @type {import("./actions/announce-thread")}) */
const announceThread = sync.require("./actions/announce-thread")
/** @type {import("./actions/create-room")}) */
@ -212,15 +210,6 @@ module.exports = {
await addReaction.addReaction(data)
},
/**
* @param {import("./discord-client")} client
* @param {import("discord-api-types/v10").GatewayMessageReactionAddDispatchData} data
*/
async onReactionRemove(client, data) {
if (data.user_id === client.user.id) return // m2d reactions are added by the discord bot user - do not reflect them back to matrix.
await removeReaction.removeReaction(data)
},
/**
* @param {import("./discord-client")} client
* @param {import("discord-api-types/v10").GatewayMessageDeleteDispatchData} data

View file

@ -21,19 +21,16 @@ async function addReaction(event) {
let discordPreferredEncoding
if (emoji.startsWith("mxc://")) {
// Custom emoji
let row = select("emoji", ["id", "name"], "WHERE mxc_url = ?").get(emoji)
if (!row && event.content.shortcode) {
// Use the name to try to find a known emoji with the same name.
const name = event.content.shortcode.replace(/^:|:$/g, "")
row = select("emoji", ["id", "name"], "WHERE name = ?").get(name)
}
if (!row) {
const row = select("emoji", ["id", "name"], "WHERE mxc_url = ?").get(emoji)
if (row) {
// Great, we know exactly what this emoji is!
discordPreferredEncoding = encodeURIComponent(`${row.name}:${row.id}`)
} else {
// We don't have this emoji and there's no realistic way to just-in-time upload a new emoji somewhere.
// We can't try using a known emoji with the same name because we don't even know what the name is. We only have the mxc url.
// Sucks!
return
}
// Cool, we got an exact or a candidate emoji.
discordPreferredEncoding = encodeURIComponent(`${row.name}:${row.id}`)
} else {
// Default emoji
// https://github.com/discord/discord-api-docs/issues/2723#issuecomment-807022205 ????????????

View file

@ -24,8 +24,7 @@ async function removeReaction(event) {
const hash = utils.getEventIDHash(event.redacts)
const row = from("reaction").join("message_channel", "message_id").select("channel_id", "message_id", "encoded_emoji").and("WHERE hashed_event_id = ?").get(hash)
if (!row) return
await discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji)
db.prepare("DELETE FROM reaction WHERE hashed_event_id = ?").run(hash)
return discord.snow.channel.deleteReactionSelf(row.channel_id, row.message_id, row.encoded_emoji)
}
/**

View file

@ -155,10 +155,7 @@ async function sendEvent(roomID, type, content, mxid, timestamp) {
}
/**
* @param {string} roomID
* @param {string} eventID
* @param {string?} [mxid]
* @returns {Promise<string>} event ID
* @returns {Promise<string>} room ID
*/
async function redactEvent(roomID, eventID, mxid) {
/** @type {Ty.R.EventRedacted} */

3
types.d.ts vendored
View file

@ -171,8 +171,7 @@ export namespace Event {
rel_type: "m.annotation"
event_id: string // the event that was reacted to
key: string // the unicode emoji, mxc uri, or reaction text
},
"shortcode"?: string // starts and ends with colons
}
}
export type Outer_M_Room_Redaction = Outer<{