diff --git a/bridge/config/config.go b/bridge/config/config.go index ae937915..7e6786a8 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -27,6 +27,7 @@ type Message struct { Protocol string `json:"protocol"` Gateway string `json:"gateway"` Timestamp time.Time `json:"timestamp"` + ID string `json:"id"` } type ChannelInfo struct { diff --git a/bridge/discord/discord.go b/bridge/discord/discord.go index b44ad898..ffbada40 100644 --- a/bridge/discord/discord.go +++ b/bridge/discord/discord.go @@ -129,20 +129,27 @@ func (b *bdiscord) Send(msg config.Message) (string, error) { if wID == "" { flog.Debugf("Broadcasting using token (API)") - b.c.ChannelMessageSend(channelID, msg.Username+msg.Text) - } else { - flog.Debugf("Broadcasting using Webhook") - b.c.WebhookExecute( - wID, - wToken, - true, - &discordgo.WebhookParams{ - Content: msg.Text, - Username: msg.Username, - AvatarURL: msg.Avatar, - }) + if msg.ID != "" { + _, 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 } - return "", nil + flog.Debugf("Broadcasting using Webhook") + err := b.c.WebhookExecute( + wID, + wToken, + true, + &discordgo.WebhookParams{ + Content: msg.Text, + Username: msg.Username, + AvatarURL: msg.Avatar, + }) + return "", err } 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", - UserID: m.Author.ID} + UserID: m.Author.ID, ID: m.ID} rmsg.Channel = b.getChannelName(m.ChannelID) if b.UseChannelID { diff --git a/bridge/mattermost/mattermost.go b/bridge/mattermost/mattermost.go index e7f125bd..6bc1ebb7 100644 --- a/bridge/mattermost/mattermost.go +++ b/bridge/mattermost/mattermost.go @@ -23,6 +23,7 @@ type MMMessage struct { Channel string Username string UserID string + ID string } type Bmattermost struct { @@ -162,8 +163,10 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) { } return "", nil } - b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message) - return "", nil + if msg.ID != "" { + return b.mc.EditMessage(msg.ID, message) + } + return b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message) } func (b *Bmattermost) handleMatter() { @@ -180,7 +183,7 @@ func (b *Bmattermost) handleMatter() { go b.handleMatterClient(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) if ok { rmsg.Event = config.EVENT_USER_ACTION @@ -218,6 +221,7 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) { m.Username = message.Username m.Channel = message.Channel m.Text = message.Text + m.ID = message.Post.Id if message.Raw.Event == "post_edited" && !b.Config.EditDisable { m.Text = message.Text + b.Config.EditSuffix } diff --git a/gateway/gateway.go b/gateway/gateway.go index a7fc4116..1d112811 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -6,6 +6,7 @@ import ( "github.com/42wim/matterbridge/bridge/config" log "github.com/Sirupsen/logrus" // "github.com/davecgh/go-spew/spew" + "github.com/hashicorp/golang-lru" "github.com/peterhellberg/emojilib" "regexp" "strings" @@ -21,10 +22,12 @@ type Gateway struct { ChannelOptions map[string]config.ChannelOptions Message chan config.Message Name string - Messages map[string][]*BridgeMsg + Messages *lru.Cache + //map[string][]*BrMsg + lruCache *lru.Cache } -type BridgeMsg struct { +type BrMsgID struct { br *bridge.Bridge ID string } @@ -32,6 +35,8 @@ type BridgeMsg struct { func New(cfg config.Gateway, r *Router) *Gateway { gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message, Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config} + cache, _ := lru.New(5000) + gw.Messages = cache gw.AddConfig(&cfg) return gw } @@ -142,15 +147,16 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con 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 if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart { - return + return brMsgIDs } // broadcast to every out channel (irc QUIT) if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE { log.Debug("empty channel") - return + return brMsgIDs } originchannel := msg.Channel origmsg := msg @@ -164,15 +170,28 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { msg.Channel = channel.Name msg.Avatar = gw.modifyAvatar(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 if dest.Protocol == "api" { msg.Channel = originchannel } - _, err := dest.Send(msg) + mID, err := dest.Send(msg) if err != nil { 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 { diff --git a/gateway/router.go b/gateway/router.go index 167e2057..56518e6c 100644 --- a/gateway/router.go +++ b/gateway/router.go @@ -94,11 +94,17 @@ func (r *Router) handleReceive() { } } for _, gw := range r.Gateways { + // record all the message ID's of the different bridges + var msgIDs []*BrMsgID if !gw.ignoreMessage(&msg) { msg.Timestamp = time.Now() gw.modifyMessage(&msg) 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) } } }