mirror of
https://github.com/cwinfo/matterbridge.git
synced 2024-12-28 12:35:40 +00:00
ed01820722
Currently fully support mattermost,slack and discord. Message deleted on the bridge or received from other bridges will be deleted. Partially support for Gitter. Gitter bridge will delete messages received from other bridges. But if you delete a message on gitter, this deletion will not be sent to other bridges (this is a gitter API limitation, it doesn't propogate edits or deletes via the API)
183 lines
4.0 KiB
Go
183 lines
4.0 KiB
Go
package bxmpp
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"github.com/42wim/matterbridge/bridge/config"
|
|
log "github.com/Sirupsen/logrus"
|
|
"github.com/jpillora/backoff"
|
|
"github.com/mattn/go-xmpp"
|
|
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Bxmpp struct {
|
|
xc *xmpp.Client
|
|
xmppMap map[string]string
|
|
Config *config.Protocol
|
|
Remote chan config.Message
|
|
Account string
|
|
}
|
|
|
|
var flog *log.Entry
|
|
var protocol = "xmpp"
|
|
|
|
func init() {
|
|
flog = log.WithFields(log.Fields{"module": protocol})
|
|
}
|
|
|
|
func New(cfg config.Protocol, account string, c chan config.Message) *Bxmpp {
|
|
b := &Bxmpp{}
|
|
b.xmppMap = make(map[string]string)
|
|
b.Config = &cfg
|
|
b.Account = account
|
|
b.Remote = c
|
|
return b
|
|
}
|
|
|
|
func (b *Bxmpp) Connect() error {
|
|
var err error
|
|
flog.Infof("Connecting %s", b.Config.Server)
|
|
b.xc, err = b.createXMPP()
|
|
if err != nil {
|
|
flog.Debugf("%#v", err)
|
|
return err
|
|
}
|
|
flog.Info("Connection succeeded")
|
|
go func() {
|
|
initial := true
|
|
bf := &backoff.Backoff{
|
|
Min: time.Second,
|
|
Max: 5 * time.Minute,
|
|
Jitter: true,
|
|
}
|
|
for {
|
|
if initial {
|
|
b.handleXmpp()
|
|
initial = false
|
|
}
|
|
d := bf.Duration()
|
|
flog.Infof("Disconnected. Reconnecting in %s", d)
|
|
time.Sleep(d)
|
|
b.xc, err = b.createXMPP()
|
|
if err == nil {
|
|
b.Remote <- config.Message{Username: "system", Text: "rejoin", Channel: "", Account: b.Account, Event: config.EVENT_REJOIN_CHANNELS}
|
|
b.handleXmpp()
|
|
bf.Reset()
|
|
}
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func (b *Bxmpp) Disconnect() error {
|
|
return nil
|
|
}
|
|
|
|
func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error {
|
|
b.xc.JoinMUCNoHistory(channel.Name+"@"+b.Config.Muc, b.Config.Nick)
|
|
return nil
|
|
}
|
|
|
|
func (b *Bxmpp) Send(msg config.Message) (string, error) {
|
|
// ignore delete messages
|
|
if msg.Event == config.EVENT_MSG_DELETE {
|
|
return "", nil
|
|
}
|
|
flog.Debugf("Receiving %#v", msg)
|
|
b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text})
|
|
return "", nil
|
|
}
|
|
|
|
func (b *Bxmpp) createXMPP() (*xmpp.Client, error) {
|
|
tc := new(tls.Config)
|
|
tc.InsecureSkipVerify = b.Config.SkipTLSVerify
|
|
tc.ServerName = strings.Split(b.Config.Server, ":")[0]
|
|
options := xmpp.Options{
|
|
Host: b.Config.Server,
|
|
User: b.Config.Jid,
|
|
Password: b.Config.Password,
|
|
NoTLS: true,
|
|
StartTLS: true,
|
|
TLSConfig: tc,
|
|
|
|
//StartTLS: false,
|
|
Debug: true,
|
|
Session: true,
|
|
Status: "",
|
|
StatusMessage: "",
|
|
Resource: "",
|
|
InsecureAllowUnencryptedAuth: false,
|
|
//InsecureAllowUnencryptedAuth: true,
|
|
}
|
|
var err error
|
|
b.xc, err = options.NewClient()
|
|
return b.xc, err
|
|
}
|
|
|
|
func (b *Bxmpp) xmppKeepAlive() chan bool {
|
|
done := make(chan bool)
|
|
go func() {
|
|
ticker := time.NewTicker(90 * time.Second)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
flog.Debugf("PING")
|
|
err := b.xc.PingC2S("", "")
|
|
if err != nil {
|
|
flog.Debugf("PING failed %#v", err)
|
|
}
|
|
case <-done:
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
return done
|
|
}
|
|
|
|
func (b *Bxmpp) handleXmpp() error {
|
|
var ok bool
|
|
done := b.xmppKeepAlive()
|
|
defer close(done)
|
|
nodelay := time.Time{}
|
|
for {
|
|
m, err := b.xc.Recv()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
switch v := m.(type) {
|
|
case xmpp.Chat:
|
|
var channel, nick string
|
|
if v.Type == "groupchat" {
|
|
s := strings.Split(v.Remote, "@")
|
|
if len(s) >= 2 {
|
|
channel = s[0]
|
|
}
|
|
s = strings.Split(s[1], "/")
|
|
if len(s) == 2 {
|
|
nick = s[1]
|
|
}
|
|
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)
|
|
b.Remote <- rmsg
|
|
}
|
|
}
|
|
case xmpp.Presence:
|
|
// do nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
func (b *Bxmpp) replaceAction(text string) (string, bool) {
|
|
if strings.HasPrefix(text, "/me ") {
|
|
return strings.Replace(text, "/me ", "", -1), true
|
|
}
|
|
return text, false
|
|
}
|