From 1c3223387aaf78ba5637f58ca57bd8206ad0446c Mon Sep 17 00:00:00 2001 From: Vyquos <75266055+Vyquos@users.noreply.github.com> Date: Wed, 12 Oct 2022 22:50:08 +0200 Subject: [PATCH 1/2] Change misleading variable name Rename "editEventId" to "editedEventId" in DiscordBot.edit. The id string that's handed to the function as an argument is the id of the original message event, while 'event.event_id' is the actual replace/edit-event. --- src/bot.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index fc575cd8..3c3f5e90 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -516,12 +516,12 @@ export class DiscordBot { opts: Discord.MessageOptions, roomLookup: ChannelLookupResult, event: IMatrixEvent, - editEventId: string, + editedEventId: string, ): Promise { const chan = roomLookup.channel; const botUser = roomLookup.botUser; const embed = embedSet.messageEmbed; - const oldMsg = await chan.messages.fetch(editEventId); + const oldMsg = await chan.messages.fetch(editedEventId); if (!oldMsg) { // old message not found, just sending this normally await this.send(embedSet, opts, roomLookup, event); @@ -541,12 +541,12 @@ export class DiscordBot { } } try { - if (editEventId === this.lastEventIds[chan.id]) { + if (editedEventId === this.lastEventIds[chan.id]) { log.info("Immediate edit, deleting and re-sending"); this.channelLock.set(chan.id); // we need to delete the event off of the store // else the delete bridges over back to matrix - const dbEvent = await this.store.Get(DbEvent, { discord_id: editEventId }); + const dbEvent = await this.store.Get(DbEvent, { discord_id: editedEventId }); log.verbose("Event to delete", dbEvent); if (dbEvent && dbEvent.Next()) { await this.store.Delete(dbEvent); @@ -566,7 +566,7 @@ export class DiscordBot { }); return; } - const link = `https://discord.com/channels/${chan.guild.id}/${chan.id}/${editEventId}`; + const link = `https://discord.com/channels/${chan.guild.id}/${chan.id}/${editedEventId}`; embedSet.messageEmbed.description = `[Edit](${link}): ${embedSet.messageEmbed.description}`; await this.send(embedSet, opts, roomLookup, event); } catch (err) { From f8e9449908b332d97f11932fb835552adca0aa5b Mon Sep 17 00:00:00 2001 From: Vyquos <75266055+Vyquos@users.noreply.github.com> Date: Wed, 12 Oct 2022 22:51:24 +0200 Subject: [PATCH 2/2] Bridge edits to discord webhooks Support M->D edit bridging via the native discord webhook endpoint Fixes issue #644 --- src/bot.ts | 114 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 46 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index 3c3f5e90..44e4226f 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -539,41 +539,78 @@ export class DiscordBot { } catch (err) { log.warning("Failed to edit discord message, falling back to delete and resend...", err); } + } else { + let hook = await this.getWebhook(chan); + try { + if (hook) { + // do we need to delete the event off of the store? + // the edit may bridge over back to matrix otherwise + const embeds = this.prepareEmbedSetWebhook(embedSet); + hook.editMessage(oldMsg, embed.description, { + avatarURL: embed!.author!.iconURL, + embeds, + files: opts.files, + username: embed!.author!.name, + }) + this.channelLock.release(chan.id); + } else { + // fallback: use the old method for editing messages of + // simply (re)sending them. + if (editedEventId === this.lastEventIds[chan.id]) { + log.info("Immediate edit, deleting and re-sending"); + this.channelLock.set(chan.id); + // we need to delete the event off of the store + // else the delete bridges over back to matrix + const dbEvent = await this.store.Get(DbEvent, { discord_id: editedEventId }); + log.verbose("Event to delete", dbEvent); + if (dbEvent && dbEvent.Next()) { + await this.store.Delete(dbEvent); + } + await oldMsg.delete(); + this.channelLock.release(chan.id); + const msg = await this.send(embedSet, opts, roomLookup, event, true); + // we re-insert the old matrix event with the new discord id + // to allow consecutive edits, as matrix edits are typically + // done on the original event + const dummyEvent = { + event_id: event.content!["m.relates_to"].event_id, + room_id: event.room_id, + } as IMatrixEvent; + this.StoreMessagesSent(msg, chan, dummyEvent).catch(() => { + log.warn("Failed to store edit sent message for ", event.event_id); + }); + return; + } + const link = `https://discord.com/channels/${chan.guild.id}/${chan.id}/${editedEventId}`; + embedSet.messageEmbed.description = `[Edit](${link}): ${embedSet.messageEmbed.description}`; + await this.send(embedSet, opts, roomLookup, event); + } + } catch (err) { + // throw wrapError(err, Unstable.ForeignNetworkError, "Couldn't edit message"); + log.warn(`Failed to edit message ${event.event_id}`); + log.verbose(err); + } } + } + + public async getWebhook(channel: Discord.TextChannel): Promise { + const webhooks = await channel.fetchWebhooks(); + let hook: Discord.Webhook | undefined = webhooks.filter((h) => h.name === "_matrix").first(); + // Create a new webhook if none already exists try { - if (editedEventId === this.lastEventIds[chan.id]) { - log.info("Immediate edit, deleting and re-sending"); - this.channelLock.set(chan.id); - // we need to delete the event off of the store - // else the delete bridges over back to matrix - const dbEvent = await this.store.Get(DbEvent, { discord_id: editedEventId }); - log.verbose("Event to delete", dbEvent); - if (dbEvent && dbEvent.Next()) { - await this.store.Delete(dbEvent); - } - await oldMsg.delete(); - this.channelLock.release(chan.id); - const msg = await this.send(embedSet, opts, roomLookup, event, true); - // we re-insert the old matrix event with the new discord id - // to allow consecutive edits, as matrix edits are typically - // done on the original event - const dummyEvent = { - event_id: event.content!["m.relates_to"].event_id, - room_id: event.room_id, - } as IMatrixEvent; - this.StoreMessagesSent(msg, chan, dummyEvent).catch(() => { - log.warn("Failed to store edit sent message for ", event.event_id); - }); - return; + if (!hook) { + hook = await channel.createWebhook( + "_matrix", + { + avatar: MATRIX_ICON_URL, + reason: "Matrix Bridge: Allow rich user messages", + }); } - const link = `https://discord.com/channels/${chan.guild.id}/${chan.id}/${editedEventId}`; - embedSet.messageEmbed.description = `[Edit](${link}): ${embedSet.messageEmbed.description}`; - await this.send(embedSet, opts, roomLookup, event); } catch (err) { - // throw wrapError(err, Unstable.ForeignNetworkError, "Couldn't edit message"); - log.warn(`Failed to edit message ${event.event_id}`); - log.verbose(err); + // throw wrapError(err, Unstable.ForeignNetworkError, "Unable to create \"_matrix\" webhook"); + log.warn("Unable to create _matrix webook:", err); } + return hook } /** @@ -594,22 +631,7 @@ export class DiscordBot { let msg: Discord.Message | null | (Discord.Message | null)[] = null; let hook: Discord.Webhook | undefined; if (botUser) { - const webhooks = await chan.fetchWebhooks(); - hook = webhooks.filter((h) => h.name === "_matrix").first(); - // Create a new webhook if none already exists - try { - if (!hook) { - hook = await chan.createWebhook( - "_matrix", - { - avatar: MATRIX_ICON_URL, - reason: "Matrix Bridge: Allow rich user messages", - }); - } - } catch (err) { - // throw wrapError(err, Unstable.ForeignNetworkError, "Unable to create \"_matrix\" webhook"); - log.warn("Unable to create _matrix webook:", err); - } + hook = await this.getWebhook(chan); } try { this.channelLock.set(chan.id);