forked from lug/matterbridge
		
	Update webhook messages via new endpoint (discord)
When using the webhook, the previous method to edit a message was to delete the old one via the classical API, and to create a new message via the webhook. While this works, this means that editing "old" messages lead to a mess where the chronological order is no longer respected. This uses an hidden API explained in https://support.discord.com/hc/en-us/community/posts/360034557771 to achieve a proper edition using the webhook API. The obvious downside of this approach is that since it is an undocumented API for now, so there is no stability guarantee :/
This commit is contained in:
		| @@ -34,8 +34,6 @@ type Bdiscord struct { | |||||||
| 	membersMutex  sync.RWMutex | 	membersMutex  sync.RWMutex | ||||||
| 	userMemberMap map[string]*discordgo.Member | 	userMemberMap map[string]*discordgo.Member | ||||||
| 	nickMemberMap map[string]*discordgo.Member | 	nickMemberMap map[string]*discordgo.Member | ||||||
| 	webhookCache  map[string]string |  | ||||||
| 	webhookMutex  sync.RWMutex |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func New(cfg *bridge.Config) bridge.Bridger { | func New(cfg *bridge.Config) bridge.Bridger { | ||||||
| @@ -43,7 +41,6 @@ func New(cfg *bridge.Config) bridge.Bridger { | |||||||
| 	b.userMemberMap = make(map[string]*discordgo.Member) | 	b.userMemberMap = make(map[string]*discordgo.Member) | ||||||
| 	b.nickMemberMap = make(map[string]*discordgo.Member) | 	b.nickMemberMap = make(map[string]*discordgo.Member) | ||||||
| 	b.channelInfoMap = make(map[string]*config.ChannelInfo) | 	b.channelInfoMap = make(map[string]*config.ChannelInfo) | ||||||
| 	b.webhookCache = make(map[string]string) |  | ||||||
| 	if b.GetString("WebhookURL") != "" { | 	if b.GetString("WebhookURL") != "" { | ||||||
| 		b.Log.Debug("Configuring Discord Incoming Webhook") | 		b.Log.Debug("Configuring Discord Incoming Webhook") | ||||||
| 		b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL")) | 		b.webhookID, b.webhookToken = b.splitURL(b.GetString("WebhookURL")) | ||||||
| @@ -191,8 +188,6 @@ func (b *Bdiscord) JoinChannel(channel config.ChannelInfo) error { | |||||||
| func (b *Bdiscord) Send(msg config.Message) (string, error) { | func (b *Bdiscord) Send(msg config.Message) (string, error) { | ||||||
| 	b.Log.Debugf("=> Receiving %#v", msg) | 	b.Log.Debugf("=> Receiving %#v", msg) | ||||||
|  |  | ||||||
| 	origMsgID := msg.ID |  | ||||||
|  |  | ||||||
| 	channelID := b.getChannelID(msg.Channel) | 	channelID := b.getChannelID(msg.Channel) | ||||||
| 	if channelID == "" { | 	if channelID == "" { | ||||||
| 		return "", fmt.Errorf("Could not find channelID for %v", msg.Channel) | 		return "", fmt.Errorf("Could not find channelID for %v", msg.Channel) | ||||||
| @@ -233,18 +228,6 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) { | |||||||
| 			return "", nil | 			return "", nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// If we are editing a message, delete the old message |  | ||||||
| 		if msg.ID != "" { |  | ||||||
| 			msg.ID = b.getCacheID(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") |  | ||||||
|  |  | ||||||
| 		// skip empty messages | 		// skip empty messages | ||||||
| 		if msg.Text == "" && (msg.Extra == nil || len(msg.Extra["file"]) == 0) { | 		if msg.Text == "" && (msg.Extra == nil || len(msg.Extra["file"]) == 0) { | ||||||
| 			b.Log.Debugf("Skipping empty message %#v", msg) | 			b.Log.Debugf("Skipping empty message %#v", msg) | ||||||
| @@ -257,11 +240,25 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) { | |||||||
| 		if len(msg.Username) > 32 { | 		if len(msg.Username) > 32 { | ||||||
| 			msg.Username = msg.Username[0:32] | 			msg.Username = msg.Username[0:32] | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if msg.ID != "" { | ||||||
|  | 			b.Log.Debugf("Editing webhook message") | ||||||
|  | 			uri := discordgo.EndpointWebhookToken(wID, wToken) + "/messages/" + msg.ID | ||||||
|  | 			_, err := b.c.RequestWithBucketID("PATCH", uri, discordgo.WebhookParams{ | ||||||
|  | 				Content:  msg.Text, | ||||||
|  | 				Username: msg.Username, | ||||||
|  | 			}, discordgo.EndpointWebhookToken("", "")) | ||||||
|  | 			if err == nil { | ||||||
|  | 				return msg.ID, nil | ||||||
|  | 			} | ||||||
|  | 			b.Log.Errorf("Could not edit webhook message: %s", err) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		b.Log.Debugf("Broadcasting using Webhook") | ||||||
|  |  | ||||||
| 		// if we have a global webhook for this Discord account, and permission | 		// if we have a global webhook for this Discord account, and permission | ||||||
| 		// to modify webhooks (previously verified), then set its channel to | 		// to modify webhooks (previously verified), then set its channel to | ||||||
| 		// the message channel before using it | 		// the message channel before using it. | ||||||
| 		// TODO: this isn't necessary if the last message from this webhook was |  | ||||||
| 		// sent to the current channel |  | ||||||
| 		if isGlobalWebhook && b.canEditWebhooks { | 		if isGlobalWebhook && b.canEditWebhooks { | ||||||
| 			b.Log.Debugf("Setting webhook channel to \"%s\"", msg.Channel) | 			b.Log.Debugf("Setting webhook channel to \"%s\"", msg.Channel) | ||||||
| 			_, err := b.c.WebhookEdit(wID, "", "", channelID) | 			_, err := b.c.WebhookEdit(wID, "", "", channelID) | ||||||
| @@ -280,7 +277,6 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) { | |||||||
| 			return "", nil | 			return "", nil | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		b.updateCacheID(origMsgID, msg.ID) |  | ||||||
| 		return msg.ID, nil | 		return msg.ID, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -291,7 +287,6 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) { | |||||||
| 		if msg.ID == "" { | 		if msg.ID == "" { | ||||||
| 			return "", nil | 			return "", nil | ||||||
| 		} | 		} | ||||||
| 		msg.ID = b.getCacheID(msg.ID) |  | ||||||
| 		err := b.c.ChannelMessageDelete(channelID, msg.ID) | 		err := b.c.ChannelMessageDelete(channelID, msg.ID) | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -209,40 +209,6 @@ func (b *Bdiscord) splitURL(url string) (string, string) { | |||||||
| 	return webhookURLSplit[webhookIdxID], webhookURLSplit[webhookIdxToken] | 	return webhookURLSplit[webhookIdxID], webhookURLSplit[webhookIdxToken] | ||||||
| } | } | ||||||
|  |  | ||||||
| // getcacheID tries to find a corresponding msgID in the webhook cache. |  | ||||||
| // if not found returns the original request. |  | ||||||
| func (b *Bdiscord) getCacheID(msgID string) string { |  | ||||||
| 	b.webhookMutex.RLock() |  | ||||||
| 	defer b.webhookMutex.RUnlock() |  | ||||||
| 	for k, v := range b.webhookCache { |  | ||||||
| 		if msgID == k { |  | ||||||
| 			return v |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return msgID |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // updateCacheID updates the cache so that the newID takes the place of |  | ||||||
| // the original ID. This is used for edit/deletes in combination with webhooks |  | ||||||
| // as editing a message via webhook means deleting the message and creating a |  | ||||||
| // new message (with a new ID). This ID needs to be set instead of the original ID |  | ||||||
| func (b *Bdiscord) updateCacheID(origID, newID string) { |  | ||||||
| 	b.webhookMutex.Lock() |  | ||||||
| 	match := false |  | ||||||
| 	for k, v := range b.webhookCache { |  | ||||||
| 		if v == origID { |  | ||||||
| 			delete(b.webhookCache, k) |  | ||||||
| 			b.webhookCache[origID] = newID |  | ||||||
| 			match = true |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if !match && origID != "" { |  | ||||||
| 		b.webhookCache[origID] = newID |  | ||||||
| 	} |  | ||||||
| 	b.webhookMutex.Unlock() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func enumerateUsernames(s string) []string { | func enumerateUsernames(s string) []string { | ||||||
| 	onlySpace := true | 	onlySpace := true | ||||||
| 	for _, r := range s { | 	for _, r := range s { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Simon THOBY
					Simon THOBY