Thumbnail

rani/matterbridge.git

Clone URL: https://git.buni.party/rani/matterbridge.git

commit 94f2924a8f3c618ac4e1e6d63008aa22866eddd2 Author: Qais Patankar <qaisjp@gmail.com> Date: Tue Jul 09 05:18:37 2019 +0000 Support webhook message deletions (discord) (#853) * Support webhook message deletions (discord) Messages sent via webhook can now be deleted. It seems it can do this without any special permissions. This copies discordgo.WebhookExecute and makes it support the returning of discordgo.Message. A pull request has been sent upstream, so we should use that if @bwmariin accepts the pull request: https://github.com/bwmarrin/discordgo/pull/663 Changes in behaviour (webhook mode only): - Previously messages *edited* on other platforms would just be retransmitted as a brand new message to Discord. - Message *edits* will now be ignored. - Debug: message edits will now print out a "permission error". In the future it may be good to send an "message edited" react to those webhook messages, so at least people know that the message was edited on other platforms. (Even though it can't actually show the new message.) Alternatively, message edits could just send a brand new message with a link back to the old one. This is a little ugly but it would ensure that Discord users are able to see the edited message. These "message edit notifications" would be sent from the bot user (not from a webhook), so we could edit the "edit notification" if subsequent edits to the original message are made. diff --git a/bridge/discord/discord.go b/bridge/discord/discord.go index ea43bd2..4c1c0f4 100644 --- a/bridge/discord/discord.go +++ b/bridge/discord/discord.go @@ -20911 +20921 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {   b.channelsMutex.RUnlock()     // Use webhook to send the message - if wID != "" { + if wID != "" && msg.Event != config.EventMsgDelete {   // skip events   if msg.Event != "" && msg.Event != config.EventJoinLeave && msg.Event != config.EventTopicChange {   return "", nil   } + + // If we are editing a message, delete the old message + if msg.ID != "" { + b.Log.Debugf("Deleting edited webhook message") + err := b.c.ChannelMessageDelete(channelID, msg.ID) + if err != nil { + b.Log.Errorf("Could not delete edited webhook message: %s", err) + } + } +   b.Log.Debugf("Broadcasting using Webhook")   for _, f := range msg.Extra["file"] {   fi := f.(config.FileInfo) @@ -2517 +2617 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {   return "", err   }   } - err := b.c.WebhookExecute( + msg, err := b.webhookExecute(   wID,   wToken,   true, @@ -2607 +2707 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) {   Username: msg.Username,   AvatarURL: msg.Avatar,   }) - return "", err + return msg.ID, err   }     b.Log.Debugf("Broadcasting using token (API)") diff --git a/bridge/discord/helpers.go b/bridge/discord/helpers.go index 7b06081..e150d19 100644 --- a/bridge/discord/helpers.go +++ b/bridge/discord/helpers.go @@ -16 +17 @@  package bdiscord    import ( + "encoding/json"   "errors"   "regexp"   "strings" @@ -1873 +18826 @@ func enumerateUsernames(s string) []string {   }   return usernames  } + +// webhookExecute executes a webhook. +// webhookID: The ID of a webhook. +// token : The auth token for the webhook +// wait : Waits for server confirmation of message send and ensures that the return struct is populated (it is nil otherwise) +func (b *Bdiscord) webhookExecute(webhookID, token string, wait bool, data *discordgo.WebhookParams) (st *discordgo.Message, err error) { + uri := discordgo.EndpointWebhookToken(webhookID, token) + + if wait { + uri += "?wait=true" + } + response, err := b.c.RequestWithBucketID("POST", uri, data, discordgo.EndpointWebhookToken("", "")) + if !wait || err != nil { + return nil, err + } + + err = json.Unmarshal(response, &st) + if err != nil { + return nil, discordgo.ErrJSONUnmarshal + } + + return st, nil +} diff --git a/gateway/router.go b/gateway/router.go index 613a2c4..3d53167 100644 --- a/gateway/router.go +++ b/gateway/router.go @@ -1257 +1258 @@ func (r *Router) handleReceive() {   r.handleEventGetChannelMembers(&msg)   r.handleEventFailure(&msg)   r.handleEventRejoinChannels(&msg) - idx := 0 + + filesHandled := false   for _, gw := range r.Gateways {   // record all the message ID's of the different bridges   var msgIDs []*BrMsgID @@ -13417 +13526 @@ func (r *Router) handleReceive() {   }   msg.Timestamp = time.Now()   gw.modifyMessage(&msg) - if idx == 0 { + if !filesHandled {   gw.handleFiles(&msg) + filesHandled = true   }   for _, br := range gw.Bridges {   msgIDs = append(msgIDs, gw.handleMessage(&msg, br)...)   } - // only add the message ID if it doesn't already exists - if _, ok := gw.Messages.Get(msg.Protocol + " " + msg.ID); !ok && msg.ID != "" { - gw.Messages.Add(msg.Protocol+" "+msg.ID, msgIDs) + + if msg.ID != "" { + _, exists := gw.Messages.Get(msg.Protocol + " " + msg.ID) + + // Only add the message ID if it doesn't already exist + // + // For some bridges we always add/update the message ID. + // This is necessary as msgIDs will change if a bridge returns + // a different ID in response to edits. + if !exists || msg.Protocol == "discord" { + gw.Messages.Add(msg.Protocol+" "+msg.ID, msgIDs) + }   } - idx++   }   }  }