3
0
mirror of https://github.com/42wim/matterbridge.git synced 2024-12-22 19:22:38 +01:00

Add action support for slack,mattermost,irc,gitter,matrix,xmpp,discord.

This commit is contained in:
Wim 2017-07-30 17:48:23 +02:00
parent 54216cec4b
commit f8e6a69d6e
9 changed files with 95 additions and 15 deletions
bridge
config
discord
gitter
irc
matrix
mattermost
slack
telegram
xmpp

View File

@ -13,6 +13,7 @@ const (
EVENT_JOIN_LEAVE = "join_leave" EVENT_JOIN_LEAVE = "join_leave"
EVENT_FAILURE = "failure" EVENT_FAILURE = "failure"
EVENT_REJOIN_CHANNELS = "rejoin_channels" EVENT_REJOIN_CHANNELS = "rejoin_channels"
EVENT_USER_ACTION = "user_action"
) )
type Message struct { type Message struct {

View File

@ -116,9 +116,16 @@ func (b *bdiscord) Send(msg config.Message) error {
} }
if b.Config.WebhookURL == "" { if b.Config.WebhookURL == "" {
flog.Debugf("Broadcasting using token (API)") flog.Debugf("Broadcasting using token (API)")
if msg.Event == config.EVENT_USER_ACTION {
msg.Username = "_" + msg.Username
msg.Text = msg.Text + "_"
}
b.c.ChannelMessageSend(channelID, msg.Username+msg.Text) b.c.ChannelMessageSend(channelID, msg.Username+msg.Text)
} else { } else {
flog.Debugf("Broadcasting using Webhook") flog.Debugf("Broadcasting using Webhook")
if msg.Event == config.EVENT_USER_ACTION {
msg.Text = "_" + msg.Text + "_"
}
b.c.WebhookExecute( b.c.WebhookExecute(
b.webhookID, b.webhookID,
b.webhookToken, b.webhookToken,
@ -171,11 +178,14 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
text = m.ContentWithMentionsReplaced() text = m.ContentWithMentionsReplaced()
} }
channelName := b.getChannelName(m.ChannelID) rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg",
UserID: m.Author.ID}
rmsg.Channel = b.getChannelName(m.ChannelID)
if b.UseChannelID { if b.UseChannelID {
channelName = "ID:" + m.ChannelID rmsg.Channel = "ID:" + m.ChannelID
} }
username := b.getNick(m.Author) rmsg.Username = b.getNick(m.Author)
if b.Config.ShowEmbeds && m.Message.Embeds != nil { if b.Config.ShowEmbeds && m.Message.Embeds != nil {
for _, embed := range m.Message.Embeds { for _, embed := range m.Message.Embeds {
@ -188,10 +198,14 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
return return
} }
text, ok := b.replaceAction(text)
if ok {
rmsg.Event = config.EVENT_USER_ACTION
}
rmsg.Text = text
flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account) flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account)
b.Remote <- config.Message{Username: username, Text: text, Channel: channelName, b.Remote <- rmsg
Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg",
UserID: m.Author.ID}
} }
func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) { func (b *bdiscord) memberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) {
@ -283,6 +297,13 @@ func (b *bdiscord) replaceChannelMentions(text string) string {
return text return text
} }
func (b *bdiscord) replaceAction(text string) (string, bool) {
if strings.HasPrefix(text, "_") && strings.HasSuffix(text, "_") {
return strings.Replace(text, "_", "", -1), true
}
return text, false
}
func (b *bdiscord) stripCustomoji(text string) string { func (b *bdiscord) stripCustomoji(text string) string {
// <:doge:302803592035958784> // <:doge:302803592035958784>
re := regexp.MustCompile("<(:.*?:)[0-9]+>") re := regexp.MustCompile("<(:.*?:)[0-9]+>")

View File

@ -81,8 +81,13 @@ func (b *Bgitter) JoinChannel(channel string) error {
// check for ZWSP to see if it's not an echo // check for ZWSP to see if it's not an echo
if !strings.HasSuffix(ev.Message.Text, "") { if !strings.HasSuffix(ev.Message.Text, "") {
flog.Debugf("Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account) flog.Debugf("Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account)
b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room, rmsg := config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room,
Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username), UserID: ev.Message.From.ID} Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username), UserID: ev.Message.From.ID}
if strings.HasPrefix(ev.Message.Text, "@"+ev.Message.From.Username) {
rmsg.Event = config.EVENT_USER_ACTION
rmsg.Text = strings.Replace(rmsg.Text, "@"+ev.Message.From.Username+" ", "", -1)
}
b.Remote <- rmsg
} }
case *gitter.GitterConnectionClosed: case *gitter.GitterConnectionClosed:
flog.Errorf("connection with gitter closed for room %s", room) flog.Errorf("connection with gitter closed for room %s", room)

View File

@ -135,7 +135,7 @@ func (b *Birc) Send(msg config.Message) error {
if len(b.Local) == b.Config.MessageQueue-1 { if len(b.Local) == b.Config.MessageQueue-1 {
text = text + " <message clipped>" text = text + " <message clipped>"
} }
b.Local <- config.Message{Text: text, Username: msg.Username, Channel: msg.Channel} b.Local <- config.Message{Text: text, Username: msg.Username, Channel: msg.Channel, Event: msg.Event}
} else { } else {
flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local))
} }
@ -148,7 +148,11 @@ func (b *Birc) doSend() {
throttle := time.NewTicker(rate) throttle := time.NewTicker(rate)
for msg := range b.Local { for msg := range b.Local {
<-throttle.C <-throttle.C
b.i.Privmsg(msg.Channel, msg.Username+msg.Text) if msg.Event == config.EVENT_USER_ACTION {
b.i.Action(msg.Channel, msg.Username+msg.Text)
} else {
b.i.Privmsg(msg.Channel, msg.Username+msg.Text)
}
} }
} }
@ -244,10 +248,12 @@ func (b *Birc) handlePrivMsg(event *irc.Event) {
if event.Nick == b.Nick { if event.Nick == b.Nick {
return return
} }
rmsg := config.Message{Username: event.Nick, Channel: event.Arguments[0], Account: b.Account, UserID: event.User + "@" + event.Host}
flog.Debugf("handlePrivMsg() %s %s %#v", event.Nick, event.Message(), event) flog.Debugf("handlePrivMsg() %s %s %#v", event.Nick, event.Message(), event)
msg := "" msg := ""
if event.Code == "CTCP_ACTION" { if event.Code == "CTCP_ACTION" {
msg = event.Nick + " " // msg = event.Nick + " "
rmsg.Event = config.EVENT_USER_ACTION
} }
msg += event.Message() msg += event.Message()
// strip IRC colors // strip IRC colors
@ -276,7 +282,8 @@ func (b *Birc) handlePrivMsg(event *irc.Event) {
msg = string(output) msg = string(output)
flog.Debugf("Sending message from %s on %s to gateway", event.Arguments[0], b.Account) flog.Debugf("Sending message from %s on %s to gateway", event.Arguments[0], b.Account)
b.Remote <- config.Message{Username: event.Nick, Text: msg, Channel: event.Arguments[0], Account: b.Account, UserID: event.User + "@" + event.Host} rmsg.Text = msg
b.Remote <- rmsg
} }
func (b *Birc) handleTopicWhoTime(event *irc.Event) { func (b *Birc) handleTopicWhoTime(event *irc.Event) {

View File

@ -78,6 +78,11 @@ func (b *Bmatrix) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
channel := b.getRoomID(msg.Channel) channel := b.getRoomID(msg.Channel)
flog.Debugf("Sending to channel %s", channel) flog.Debugf("Sending to channel %s", channel)
if msg.Event == config.EVENT_USER_ACTION {
b.mc.SendMessageEvent(channel, "m.room.message",
matrix.TextMessage{"m.emote", msg.Username + msg.Text})
return nil
}
b.mc.SendText(channel, msg.Username+msg.Text) b.mc.SendText(channel, msg.Username+msg.Text)
return nil return nil
} }
@ -95,7 +100,7 @@ func (b *Bmatrix) getRoomID(channel string) string {
func (b *Bmatrix) handlematrix() error { func (b *Bmatrix) handlematrix() error {
syncer := b.mc.Syncer.(*matrix.DefaultSyncer) syncer := b.mc.Syncer.(*matrix.DefaultSyncer)
syncer.OnEventType("m.room.message", func(ev *matrix.Event) { syncer.OnEventType("m.room.message", func(ev *matrix.Event) {
if ev.Content["msgtype"].(string) == "m.text" && ev.Sender != b.UserID { if (ev.Content["msgtype"].(string) == "m.text" || ev.Content["msgtype"].(string) == "m.emote") && ev.Sender != b.UserID {
b.RLock() b.RLock()
channel, ok := b.RoomMap[ev.RoomID] channel, ok := b.RoomMap[ev.RoomID]
b.RUnlock() b.RUnlock()
@ -108,8 +113,12 @@ func (b *Bmatrix) handlematrix() error {
re := regexp.MustCompile("(.*?):.*") re := regexp.MustCompile("(.*?):.*")
username = re.ReplaceAllString(username, `$1`) username = re.ReplaceAllString(username, `$1`)
} }
rmsg := config.Message{Username: username, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account, UserID: ev.Sender}
if ev.Content["msgtype"].(string) == "m.emote" {
rmsg.Event = config.EVENT_USER_ACTION
}
flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account) flog.Debugf("Sending message from %s on %s to gateway", ev.Sender, b.Account)
b.Remote <- config.Message{Username: username, Text: ev.Content["body"].(string), Channel: channel, Account: b.Account, UserID: ev.Sender} b.Remote <- rmsg
} }
flog.Debugf("Received: %#v", ev) flog.Debugf("Received: %#v", ev)
}) })

View File

@ -6,6 +6,7 @@ import (
"github.com/42wim/matterbridge/matterclient" "github.com/42wim/matterbridge/matterclient"
"github.com/42wim/matterbridge/matterhook" "github.com/42wim/matterbridge/matterhook"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
"strings"
) )
type MMhook struct { type MMhook struct {
@ -117,6 +118,9 @@ func (b *Bmattermost) JoinChannel(channel string) error {
func (b *Bmattermost) Send(msg config.Message) error { func (b *Bmattermost) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
if msg.Event == config.EVENT_USER_ACTION {
msg.Text = "*" + msg.Text + "*"
}
nick := msg.Username nick := msg.Username
message := msg.Text message := msg.Text
channel := msg.Channel channel := msg.Channel
@ -152,8 +156,14 @@ 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}
text, ok := b.replaceAction(message.Text)
if ok {
rmsg.Event = config.EVENT_USER_ACTION
}
rmsg.Text = text
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
b.Remote <- config.Message{Text: message.Text, Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID} b.Remote <- rmsg
} }
} }
@ -226,3 +236,10 @@ func (b *Bmattermost) apiLogin() error {
go b.mc.StatusLoop() go b.mc.StatusLoop()
return nil return nil
} }
func (b *Bmattermost) replaceAction(text string) (string, bool) {
if strings.HasPrefix(text, "*") && strings.HasSuffix(text, "*") {
return strings.Replace(text, "*", "", -1), true
}
return text, false
}

View File

@ -127,6 +127,9 @@ func (b *Bslack) JoinChannel(channel string) error {
func (b *Bslack) Send(msg config.Message) error { func (b *Bslack) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
if msg.Event == config.EVENT_USER_ACTION {
msg.Text = "_" + msg.Text + "_"
}
nick := msg.Username nick := msg.Username
message := msg.Text message := msg.Text
channel := msg.Channel channel := msg.Channel
@ -231,6 +234,9 @@ func (b *Bslack) handleSlack() {
text = html.UnescapeString(text) text = html.UnescapeString(text)
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID} msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID}
if message.Raw.SubType == "me_message" {
msg.Event = config.EVENT_USER_ACTION
}
b.Remote <- msg b.Remote <- msg
} }
} }

View File

@ -77,6 +77,7 @@ func (b *Btelegram) Send(msg config.Message) error {
func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) {
for update := range updates { for update := range updates {
flog.Debugf("Receiving from telegram: %#v", update.Message)
var message *tgbotapi.Message var message *tgbotapi.Message
username := "" username := ""
channel := "" channel := ""

View File

@ -133,6 +133,7 @@ func (b *Bxmpp) xmppKeepAlive() chan bool {
} }
func (b *Bxmpp) handleXmpp() error { func (b *Bxmpp) handleXmpp() error {
var ok bool
done := b.xmppKeepAlive() done := b.xmppKeepAlive()
defer close(done) defer close(done)
nodelay := time.Time{} nodelay := time.Time{}
@ -154,8 +155,13 @@ func (b *Bxmpp) handleXmpp() error {
nick = s[1] nick = s[1]
} }
if nick != b.Config.Nick && v.Stamp == nodelay && v.Text != "" { if nick != b.Config.Nick && v.Stamp == nodelay && v.Text != "" {
rmsg := config.Message{Username: nick, Text: v.Text, Channel: channel, Account: b.Account, UserID: v.Remote}
rmsg.Text, ok = b.replaceAction(rmsg.Text)
if ok {
rmsg.Event = config.EVENT_USER_ACTION
}
flog.Debugf("Sending message from %s on %s to gateway", nick, b.Account) flog.Debugf("Sending message from %s on %s to gateway", nick, b.Account)
b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Account: b.Account, UserID: v.Remote} b.Remote <- rmsg
} }
} }
case xmpp.Presence: case xmpp.Presence:
@ -163,3 +169,10 @@ func (b *Bxmpp) handleXmpp() error {
} }
} }
} }
func (b *Bxmpp) replaceAction(text string) (string, bool) {
if strings.HasPrefix(text, "/me ") {
return strings.Replace(text, "/me ", "", -1), true
}
return text, false
}