Compare commits
2 commits
1ed40bb5f4
...
55da70f8fc
Author | SHA1 | Date | |
---|---|---|---|
55da70f8fc | |||
6a03c96984 |
6 changed files with 86 additions and 16 deletions
|
@ -61,10 +61,10 @@ module.exports = {
|
|||
formatted_body: "\u26a0 <strong>Bridged event from Discord not delivered</strong>"
|
||||
+ `<br>Gateway event: ${gatewayMessage.t}`
|
||||
+ `<br>${e.toString()}`
|
||||
+ `<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>`,
|
||||
+ `<div><details><summary>Error trace</summary>`
|
||||
+ `<pre>${stackLines.join("\n")}</pre></details></div>`
|
||||
+ `<div><details><summary>Original payload</summary>`
|
||||
+ `<pre>${util.inspect(gatewayMessage.d, false, 4, false)}</pre></details></div>`,
|
||||
"m.mentions": {
|
||||
user_ids: ["@cadence:cadence.moe"]
|
||||
}
|
||||
|
|
|
@ -29,13 +29,15 @@ async function sendEvent(event) {
|
|||
|
||||
// no need to sync the matrix member to the other side. but if I did need to, this is where I'd do it
|
||||
|
||||
const messages = await eventToMessage.eventToMessage(event, guild, {api})
|
||||
assert(Array.isArray(messages)) // sanity
|
||||
const {messagesToEdit, messagesToSend, messagesToDelete} = await eventToMessage.eventToMessage(event, guild, {api})
|
||||
|
||||
/** @type {DiscordTypes.APIMessage[]} */
|
||||
const messageResponses = []
|
||||
let eventPart = 0 // 0 is primary, 1 is supporting
|
||||
for (const message of messages) {
|
||||
// for (const message of messagesToEdit) {
|
||||
// eventPart = 1
|
||||
// TODO ...
|
||||
for (const message of messagesToSend) {
|
||||
const messageResponse = await channelWebhook.sendMessageWithWebhook(channelID, message, threadID)
|
||||
db.prepare("INSERT INTO event_message (event_id, event_type, event_subtype, message_id, channel_id, part, source) VALUES (?, ?, ?, ?, ?, ?, 0)").run(event.event_id, event.type, event.content.msgtype || null, messageResponse.id, channelID, eventPart) // source 0 = matrix
|
||||
|
||||
|
|
|
@ -130,6 +130,8 @@ async function eventToMessage(event, guild, di) {
|
|||
|
||||
let displayName = event.sender
|
||||
let avatarURL = undefined
|
||||
/** @type {string[]} */
|
||||
let messageIDsToEdit = []
|
||||
let replyLine = ""
|
||||
// Extract a basic display name from the sender
|
||||
const match = event.sender.match(/^@(.*?):/)
|
||||
|
@ -152,9 +154,37 @@ async function eventToMessage(event, guild, di) {
|
|||
// input = input.replace(/ /g, " ")
|
||||
// There is also a corresponding test to uncomment, named "event2message: whitespace is retained"
|
||||
|
||||
// Handling replies. We'll look up the data of the replied-to event from the Matrix homeserver.
|
||||
// Handling edits. If the edit was an edit of a reply, edits do not include the reply reference, so we need to fetch up to 2 more events.
|
||||
// this event ---is an edit of--> original event ---is a reply to--> past event
|
||||
await (async () => {
|
||||
const repliedToEventId = event.content["m.relates_to"]?.["m.in_reply_to"].event_id
|
||||
if (!event.content["m.new_content"]) return
|
||||
const relatesTo = event.content["m.relates_to"]
|
||||
if (!relatesTo) return
|
||||
// Check if we have a pointer to what was edited
|
||||
const relType = relatesTo.rel_type
|
||||
if (relType !== "m.replace") return
|
||||
const originalEventId = relatesTo.event_id
|
||||
if (!originalEventId) return
|
||||
console.log("a", originalEventId)
|
||||
messageIDsToEdit = db.prepare("SELECT message_id FROM event_message WHERE event_id = ? ORDER BY part").pluck().all(originalEventId)
|
||||
if (!messageIDsToEdit.length) return
|
||||
// Get the original event, then check if it was a reply
|
||||
const originalEvent = await di.api.getEvent(event.room_id, originalEventId)
|
||||
if (!originalEvent) return
|
||||
const repliedToEventId = originalEvent.content["m.relates_to"]?.["m.in_reply_to"]?.event_id
|
||||
if (!repliedToEventId) return
|
||||
console.log("c")
|
||||
// After all that, it's an edit of a reply.
|
||||
// We'll be sneaky and prepare the message data so that everything else can handle it just like original messages.
|
||||
Object.assign(event.content, event.content["m.new_content"])
|
||||
input = event.content.formatted_body || event.content.body
|
||||
relatesTo["m.in_reply_to"] = {event_id: repliedToEventId}
|
||||
})()
|
||||
|
||||
// Handling replies. We'll look up the data of the replied-to event from the Matrix homeserver.
|
||||
// Note that an <mx-reply> element is not guaranteed because this might be m.new_content.
|
||||
await (async () => {
|
||||
const repliedToEventId = event.content["m.relates_to"]?.["m.in_reply_to"]?.event_id
|
||||
if (!repliedToEventId) return
|
||||
const repliedToEvent = await di.api.getEvent(event.room_id, repliedToEventId)
|
||||
if (!repliedToEvent) return
|
||||
|
@ -173,9 +203,9 @@ async function eventToMessage(event, guild, di) {
|
|||
replyLine += `Ⓜ️**${senderName}**: `
|
||||
}
|
||||
const repliedToContent = repliedToEvent.content.formatted_body || repliedToEvent.content.body
|
||||
const contentPreviewChunks = chunk(repliedToContent.replace(/.*<\/mx-reply>/, "").replace(/(?:\n|<br>)+/g, " ").replace(/<[^>]+>/g, ""), 24)
|
||||
const contentPreviewChunks = chunk(repliedToContent.replace(/.*<\/mx-reply>/, "").replace(/(?:\n|<br>)+/g, " ").replace(/<[^>]+>/g, ""), 50)
|
||||
const contentPreview = contentPreviewChunks.length > 1 ? contentPreviewChunks[0] + "..." : contentPreviewChunks[0]
|
||||
replyLine += contentPreview + "\n"
|
||||
replyLine = `> ${replyLine}\n> ${contentPreview}\n`
|
||||
})()
|
||||
|
||||
// Handling mentions of Discord users
|
||||
|
@ -235,7 +265,21 @@ async function eventToMessage(event, guild, di) {
|
|||
avatar_url: avatarURL
|
||||
})))
|
||||
|
||||
return messages
|
||||
const messagesToEdit = []
|
||||
const messagesToSend = []
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
if (messageIDsToEdit.length) {
|
||||
messagesToEdit.push({id: messageIDsToEdit.shift(), message: messages[i]})
|
||||
} else {
|
||||
messagesToSend.push(messages[i])
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
messagesToEdit,
|
||||
messagesToSend,
|
||||
messagesToDelete: messageIDsToEdit
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.eventToMessage = eventToMessage
|
||||
|
|
|
@ -40,10 +40,10 @@ function guard(type, fn) {
|
|||
formatted_body: "\u26a0 <strong>Matrix event not delivered to Discord</strong>"
|
||||
+ `<br>Event type: ${type}`
|
||||
+ `<br>${e.toString()}`
|
||||
+ `<details><summary>Error trace</summary>`
|
||||
+ `<pre>${stackLines.join("\n")}</pre></details>`
|
||||
+ `<details><summary>Original payload</summary>`
|
||||
+ `<pre>${util.inspect(event, false, 4, false)}</pre></details>`,
|
||||
+ `<div><details><summary>Error trace</summary>`
|
||||
+ `<pre>${stackLines.join("\n")}</pre></details></div>`
|
||||
+ `<div><details><summary>Original payload</summary>`
|
||||
+ `<pre>${util.inspect(event, false, 4, false)}</pre></details></div>`,
|
||||
"m.mentions": {
|
||||
user_ids: ["@cadence:cadence.moe"]
|
||||
}
|
||||
|
|
22
notes.md
22
notes.md
|
@ -1,5 +1,27 @@
|
|||
# d2m
|
||||
|
||||
## Known issues
|
||||
|
||||
- m->d attachments do not work
|
||||
- m->d edits do not work
|
||||
- m->d spoilers do not work
|
||||
- d->m support the rest of the attachments by reading the matrix spec instead of the current approach of whitelisting mime types
|
||||
- d->m emojis do not work at all (inline chat, single emoji size, reactions, bridged state)
|
||||
- m->d code blocks have slightly too much spacing
|
||||
- m->d some reactions don't work because of the variation selector
|
||||
- <--> check whether I implemented deletions
|
||||
- rooms will be set up even if the bridge does not have permission for them, then break when it restarts and tries to reach messages
|
||||
- test private threads as part of this
|
||||
- solution part 1: calculate the permissions to see if the bot should be able to do stuff
|
||||
- solution part 2: attempt a get messages request anyway before bridging a new room, just to make sure!
|
||||
- solution part 3: revisit the permissions to add newly available rooms and to close newly inaccessible rooms
|
||||
- consider a way to jump to a timestamp by making up a discord snowflake. practical? helpful?
|
||||
- clean up and write documentation to selfhost
|
||||
- pluralkit considerations for artemis
|
||||
- consider whether to use nested spaces for channel categories and threads
|
||||
|
||||
## Mapping
|
||||
|
||||
Remember that a discord message may be transformed to multiple matrix messages.
|
||||
|
||||
A database will be used to store the discord id to matrix event id mapping. Table columns:
|
||||
|
|
2
types.d.ts
vendored
2
types.d.ts
vendored
|
@ -75,6 +75,8 @@ export namespace Event {
|
|||
"m.in_reply_to": {
|
||||
event_id: string
|
||||
}
|
||||
rel_type?: "m.replace"
|
||||
event_id?: string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue