mirror of
https://github.com/42wim/matterbridge.git
synced 2024-11-28 13:42:01 -08:00
Add support for editing messages across bridges. Currently mattermost/discord.
Our Message type has an extra ID field which contains the message ID of the specific bridge. The Send() function has been modified to return a msg ID (after the message to that specific bridge has been created). There is a lru cache of 5000 entries (message IDs). All in memory, so editing messages will only work for messages the bot has seen. Currently we go out from the idea that every message ID is unique, so we don't keep the ID separate for each bridge. (we do for each gateway though) If there's a new message from a bridge, we put that message ID in the LRU cache as key and the []*BrMsgID as value (this slice contains the message ID's of each bridge that received the new message) If there's a new message and this message ID already exists in the cache, it must be an updated message. The value from the cache gets checked for each bridge and if there is a message ID for this bridge, the ID will be added to the Message{} sent to that bridge. If the bridge sees that the ID isn't empty, it'll know it has to update the message with that specific ID instead of creating a new message.
This commit is contained in:
parent
e84417430d
commit
7c773ebae0
@ -27,6 +27,7 @@ type Message struct {
|
|||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
Gateway string `json:"gateway"`
|
Gateway string `json:"gateway"`
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
|
ID string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelInfo struct {
|
type ChannelInfo struct {
|
||||||
|
@ -129,10 +129,18 @@ func (b *bdiscord) Send(msg config.Message) (string, error) {
|
|||||||
|
|
||||||
if wID == "" {
|
if wID == "" {
|
||||||
flog.Debugf("Broadcasting using token (API)")
|
flog.Debugf("Broadcasting using token (API)")
|
||||||
b.c.ChannelMessageSend(channelID, msg.Username+msg.Text)
|
if msg.ID != "" {
|
||||||
} else {
|
_, err := b.c.ChannelMessageEdit(channelID, msg.ID, msg.Username+msg.Text)
|
||||||
|
return msg.ID, err
|
||||||
|
}
|
||||||
|
res, err := b.c.ChannelMessageSend(channelID, msg.Username+msg.Text)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return res.ID, err
|
||||||
|
}
|
||||||
flog.Debugf("Broadcasting using Webhook")
|
flog.Debugf("Broadcasting using Webhook")
|
||||||
b.c.WebhookExecute(
|
err := b.c.WebhookExecute(
|
||||||
wID,
|
wID,
|
||||||
wToken,
|
wToken,
|
||||||
true,
|
true,
|
||||||
@ -141,8 +149,7 @@ func (b *bdiscord) Send(msg config.Message) (string, error) {
|
|||||||
Username: msg.Username,
|
Username: msg.Username,
|
||||||
AvatarURL: msg.Avatar,
|
AvatarURL: msg.Avatar,
|
||||||
})
|
})
|
||||||
}
|
return "", err
|
||||||
return "", nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
|
func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) {
|
||||||
@ -185,7 +192,7 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
|
|||||||
}
|
}
|
||||||
|
|
||||||
rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg",
|
rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg",
|
||||||
UserID: m.Author.ID}
|
UserID: m.Author.ID, ID: m.ID}
|
||||||
|
|
||||||
rmsg.Channel = b.getChannelName(m.ChannelID)
|
rmsg.Channel = b.getChannelName(m.ChannelID)
|
||||||
if b.UseChannelID {
|
if b.UseChannelID {
|
||||||
|
@ -23,6 +23,7 @@ type MMMessage struct {
|
|||||||
Channel string
|
Channel string
|
||||||
Username string
|
Username string
|
||||||
UserID string
|
UserID string
|
||||||
|
ID string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Bmattermost struct {
|
type Bmattermost struct {
|
||||||
@ -162,8 +163,10 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {
|
|||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message)
|
if msg.ID != "" {
|
||||||
return "", nil
|
return b.mc.EditMessage(msg.ID, message)
|
||||||
|
}
|
||||||
|
return b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bmattermost) handleMatter() {
|
func (b *Bmattermost) handleMatter() {
|
||||||
@ -180,7 +183,7 @@ func (b *Bmattermost) handleMatter() {
|
|||||||
go b.handleMatterClient(mchan)
|
go b.handleMatterClient(mchan)
|
||||||
}
|
}
|
||||||
for message := range mchan {
|
for message := range mchan {
|
||||||
rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID}
|
rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID, ID: message.ID}
|
||||||
text, ok := b.replaceAction(message.Text)
|
text, ok := b.replaceAction(message.Text)
|
||||||
if ok {
|
if ok {
|
||||||
rmsg.Event = config.EVENT_USER_ACTION
|
rmsg.Event = config.EVENT_USER_ACTION
|
||||||
@ -218,6 +221,7 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
|
|||||||
m.Username = message.Username
|
m.Username = message.Username
|
||||||
m.Channel = message.Channel
|
m.Channel = message.Channel
|
||||||
m.Text = message.Text
|
m.Text = message.Text
|
||||||
|
m.ID = message.Post.Id
|
||||||
if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
|
if message.Raw.Event == "post_edited" && !b.Config.EditDisable {
|
||||||
m.Text = message.Text + b.Config.EditSuffix
|
m.Text = message.Text + b.Config.EditSuffix
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/42wim/matterbridge/bridge/config"
|
"github.com/42wim/matterbridge/bridge/config"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
// "github.com/davecgh/go-spew/spew"
|
// "github.com/davecgh/go-spew/spew"
|
||||||
|
"github.com/hashicorp/golang-lru"
|
||||||
"github.com/peterhellberg/emojilib"
|
"github.com/peterhellberg/emojilib"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@ -21,10 +22,12 @@ type Gateway struct {
|
|||||||
ChannelOptions map[string]config.ChannelOptions
|
ChannelOptions map[string]config.ChannelOptions
|
||||||
Message chan config.Message
|
Message chan config.Message
|
||||||
Name string
|
Name string
|
||||||
Messages map[string][]*BridgeMsg
|
Messages *lru.Cache
|
||||||
|
//map[string][]*BrMsg
|
||||||
|
lruCache *lru.Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
type BridgeMsg struct {
|
type BrMsgID struct {
|
||||||
br *bridge.Bridge
|
br *bridge.Bridge
|
||||||
ID string
|
ID string
|
||||||
}
|
}
|
||||||
@ -32,6 +35,8 @@ type BridgeMsg struct {
|
|||||||
func New(cfg config.Gateway, r *Router) *Gateway {
|
func New(cfg config.Gateway, r *Router) *Gateway {
|
||||||
gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message,
|
gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message,
|
||||||
Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config}
|
Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config}
|
||||||
|
cache, _ := lru.New(5000)
|
||||||
|
gw.Messages = cache
|
||||||
gw.AddConfig(&cfg)
|
gw.AddConfig(&cfg)
|
||||||
return gw
|
return gw
|
||||||
}
|
}
|
||||||
@ -142,15 +147,16 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
|
|||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
|
func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrMsgID {
|
||||||
|
var brMsgIDs []*BrMsgID
|
||||||
// only relay join/part when configged
|
// only relay join/part when configged
|
||||||
if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
|
if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart {
|
||||||
return
|
return brMsgIDs
|
||||||
}
|
}
|
||||||
// broadcast to every out channel (irc QUIT)
|
// broadcast to every out channel (irc QUIT)
|
||||||
if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
|
if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE {
|
||||||
log.Debug("empty channel")
|
log.Debug("empty channel")
|
||||||
return
|
return brMsgIDs
|
||||||
}
|
}
|
||||||
originchannel := msg.Channel
|
originchannel := msg.Channel
|
||||||
origmsg := msg
|
origmsg := msg
|
||||||
@ -164,15 +170,28 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
|
|||||||
msg.Channel = channel.Name
|
msg.Channel = channel.Name
|
||||||
msg.Avatar = gw.modifyAvatar(origmsg, dest)
|
msg.Avatar = gw.modifyAvatar(origmsg, dest)
|
||||||
msg.Username = gw.modifyUsername(origmsg, dest)
|
msg.Username = gw.modifyUsername(origmsg, dest)
|
||||||
|
msg.ID = ""
|
||||||
|
if res, ok := gw.Messages.Get(origmsg.ID); ok {
|
||||||
|
IDs := res.([]*BrMsgID)
|
||||||
|
for _, id := range IDs {
|
||||||
|
if dest.Protocol == id.br.Protocol {
|
||||||
|
msg.ID = id.ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// for api we need originchannel as channel
|
// for api we need originchannel as channel
|
||||||
if dest.Protocol == "api" {
|
if dest.Protocol == "api" {
|
||||||
msg.Channel = originchannel
|
msg.Channel = originchannel
|
||||||
}
|
}
|
||||||
_, err := dest.Send(msg)
|
mID, err := dest.Send(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
// append the message ID (mID) from this bridge (dest) to our brMsgIDs slice
|
||||||
|
log.Debugf("message ID: %s\n", mID)
|
||||||
|
brMsgIDs = append(brMsgIDs, &BrMsgID{dest, mID})
|
||||||
}
|
}
|
||||||
|
return brMsgIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
|
func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
|
||||||
|
@ -94,11 +94,17 @@ func (r *Router) handleReceive() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, gw := range r.Gateways {
|
for _, gw := range r.Gateways {
|
||||||
|
// record all the message ID's of the different bridges
|
||||||
|
var msgIDs []*BrMsgID
|
||||||
if !gw.ignoreMessage(&msg) {
|
if !gw.ignoreMessage(&msg) {
|
||||||
msg.Timestamp = time.Now()
|
msg.Timestamp = time.Now()
|
||||||
gw.modifyMessage(&msg)
|
gw.modifyMessage(&msg)
|
||||||
for _, br := range gw.Bridges {
|
for _, br := range gw.Bridges {
|
||||||
gw.handleMessage(msg, br)
|
msgIDs = append(msgIDs, gw.handleMessage(msg, br)...)
|
||||||
|
}
|
||||||
|
// only add the message ID if it doesn't already exists
|
||||||
|
if _, ok := gw.Messages.Get(msg.ID); !ok {
|
||||||
|
gw.Messages.Add(msg.ID, msgIDs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user