Add initial XMPP support
This commit is contained in:
parent
46faad8b57
commit
1f72ca4c4e
167
bridge/bridge.go
167
bridge/bridge.go
|
@ -5,6 +5,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"
|
||||||
|
"github.com/mattn/go-xmpp"
|
||||||
"github.com/peterhellberg/giphy"
|
"github.com/peterhellberg/giphy"
|
||||||
ircm "github.com/sorcix/irc"
|
ircm "github.com/sorcix/irc"
|
||||||
"github.com/thoj/go-ircevent"
|
"github.com/thoj/go-ircevent"
|
||||||
|
@ -26,6 +27,10 @@ type MMapi struct {
|
||||||
mmIgnoreNicks []string
|
mmIgnoreNicks []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MMxmpp struct {
|
||||||
|
xc *xmpp.Client
|
||||||
|
xmppMap map[string]string
|
||||||
|
}
|
||||||
type MMirc struct {
|
type MMirc struct {
|
||||||
i *irc.Connection
|
i *irc.Connection
|
||||||
ircNick string
|
ircNick string
|
||||||
|
@ -44,13 +49,15 @@ type Bridge struct {
|
||||||
MMhook
|
MMhook
|
||||||
MMapi
|
MMapi
|
||||||
MMirc
|
MMirc
|
||||||
|
MMxmpp
|
||||||
*Config
|
*Config
|
||||||
kind string
|
kind string
|
||||||
}
|
}
|
||||||
|
|
||||||
type FancyLog struct {
|
type FancyLog struct {
|
||||||
irc *log.Entry
|
irc *log.Entry
|
||||||
mm *log.Entry
|
mm *log.Entry
|
||||||
|
xmpp *log.Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
var flog FancyLog
|
var flog FancyLog
|
||||||
|
@ -60,6 +67,7 @@ const Legacy = "legacy"
|
||||||
func initFLog() {
|
func initFLog() {
|
||||||
flog.irc = log.WithFields(log.Fields{"module": "irc"})
|
flog.irc = log.WithFields(log.Fields{"module": "irc"})
|
||||||
flog.mm = log.WithFields(log.Fields{"module": "mattermost"})
|
flog.mm = log.WithFields(log.Fields{"module": "mattermost"})
|
||||||
|
flog.xmpp = log.WithFields(log.Fields{"module": "xmpp"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBridge(name string, config *Config, kind string) *Bridge {
|
func NewBridge(name string, config *Config, kind string) *Bridge {
|
||||||
|
@ -67,16 +75,26 @@ func NewBridge(name string, config *Config, kind string) *Bridge {
|
||||||
b := &Bridge{}
|
b := &Bridge{}
|
||||||
b.Config = config
|
b.Config = config
|
||||||
b.kind = kind
|
b.kind = kind
|
||||||
b.ircNick = b.Config.IRC.Nick
|
|
||||||
b.ircMap = make(map[string]string)
|
|
||||||
b.mmMap = make(map[string]string)
|
b.mmMap = make(map[string]string)
|
||||||
b.MMirc.names = make(map[string][]string)
|
if b.Config.General.Irc {
|
||||||
b.ircIgnoreNicks = strings.Fields(b.Config.IRC.IgnoreNicks)
|
b.ircNick = b.Config.IRC.Nick
|
||||||
b.mmIgnoreNicks = strings.Fields(b.Config.Mattermost.IgnoreNicks)
|
b.ircMap = make(map[string]string)
|
||||||
for _, val := range b.Config.Channel {
|
b.MMirc.names = make(map[string][]string)
|
||||||
b.ircMap[val.IRC] = val.Mattermost
|
b.ircIgnoreNicks = strings.Fields(b.Config.IRC.IgnoreNicks)
|
||||||
b.mmMap[val.Mattermost] = val.IRC
|
b.mmIgnoreNicks = strings.Fields(b.Config.Mattermost.IgnoreNicks)
|
||||||
|
for _, val := range b.Config.Channel {
|
||||||
|
b.ircMap[val.IRC] = val.Mattermost
|
||||||
|
b.mmMap[val.Mattermost] = val.IRC
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if b.Config.General.Xmpp {
|
||||||
|
b.xmppMap = make(map[string]string)
|
||||||
|
for _, val := range b.Config.Channel {
|
||||||
|
b.xmppMap[val.Xmpp] = val.Mattermost
|
||||||
|
b.mmMap[val.Mattermost] = val.Xmpp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if kind == Legacy {
|
if kind == Legacy {
|
||||||
b.mh = matterhook.New(b.Config.Mattermost.URL,
|
b.mh = matterhook.New(b.Config.Mattermost.URL,
|
||||||
matterhook.Config{InsecureSkipVerify: b.Config.Mattermost.SkipTLSVerify,
|
matterhook.Config{InsecureSkipVerify: b.Config.Mattermost.SkipTLSVerify,
|
||||||
|
@ -98,9 +116,25 @@ func NewBridge(name string, config *Config, kind string) *Bridge {
|
||||||
}
|
}
|
||||||
go b.mc.WsReceiver()
|
go b.mc.WsReceiver()
|
||||||
}
|
}
|
||||||
flog.irc.Info("Trying IRC connection")
|
|
||||||
b.i = b.createIRC(name)
|
if b.Config.General.Irc {
|
||||||
flog.irc.Info("Connection succeeded")
|
flog.irc.Info("Trying IRC connection")
|
||||||
|
b.i = b.createIRC(name)
|
||||||
|
flog.irc.Info("Connection succeeded")
|
||||||
|
}
|
||||||
|
if b.Config.General.Xmpp {
|
||||||
|
var err error
|
||||||
|
flog.xmpp.Info("Trying XMPP connection")
|
||||||
|
b.xc, err = b.createXMPP()
|
||||||
|
if err != nil {
|
||||||
|
flog.xmpp.Debugf("%#v", err)
|
||||||
|
panic("xmpp failure")
|
||||||
|
}
|
||||||
|
flog.xmpp.Info("Connection succeeded")
|
||||||
|
b.setupChannels()
|
||||||
|
go b.handleXmpp()
|
||||||
|
}
|
||||||
|
|
||||||
go b.handleMatter()
|
go b.handleMatter()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
@ -123,6 +157,25 @@ func (b *Bridge) createIRC(name string) *irc.Connection {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) createXMPP() (*xmpp.Client, error) {
|
||||||
|
options := xmpp.Options{
|
||||||
|
Host: b.Config.Xmpp.Server,
|
||||||
|
User: b.Config.Xmpp.Jid,
|
||||||
|
Password: b.Config.Xmpp.Password,
|
||||||
|
NoTLS: true,
|
||||||
|
StartTLS: true,
|
||||||
|
Debug: true,
|
||||||
|
Session: true,
|
||||||
|
Status: "",
|
||||||
|
StatusMessage: "",
|
||||||
|
Resource: "",
|
||||||
|
InsecureAllowUnencryptedAuth: false,
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
b.xc, err = options.NewClient()
|
||||||
|
return b.xc, err
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleNewConnection(event *irc.Event) {
|
func (b *Bridge) handleNewConnection(event *irc.Event) {
|
||||||
flog.irc.Info("Registering callbacks")
|
flog.irc.Info("Registering callbacks")
|
||||||
i := b.i
|
i := b.i
|
||||||
|
@ -147,11 +200,19 @@ func (b *Bridge) handleNewConnection(event *irc.Event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) setupChannels() {
|
func (b *Bridge) setupChannels() {
|
||||||
i := b.i
|
if b.Config.General.Irc {
|
||||||
for _, val := range b.Config.Channel {
|
for _, val := range b.Config.Channel {
|
||||||
flog.irc.Infof("Joining %s as %s", val.IRC, b.ircNick)
|
flog.irc.Infof("Joining %s as %s", val.IRC, b.ircNick)
|
||||||
i.Join(val.IRC)
|
b.i.Join(val.IRC)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if b.Config.General.Xmpp {
|
||||||
|
for _, val := range b.Config.Channel {
|
||||||
|
flog.xmpp.Infof("Joining %s as %s", val.Xmpp, b.Xmpp.Nick)
|
||||||
|
b.xc.JoinMUCNoHistory(val.Xmpp+"@"+b.Xmpp.Muc, b.Xmpp.Nick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleIrcBotCommand(event *irc.Event) bool {
|
func (b *Bridge) handleIrcBotCommand(event *irc.Event) bool {
|
||||||
|
@ -340,9 +401,11 @@ func (b *Bridge) handleMatter() {
|
||||||
if b.ignoreMessage(message.Username, message.Text, "mattermost") {
|
if b.ignoreMessage(message.Username, message.Text, "mattermost") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
username = message.Username + ": "
|
if b.Config.General.Irc {
|
||||||
if b.Config.IRC.RemoteNickFormat != "" {
|
username = message.Username + ": "
|
||||||
username = strings.Replace(b.Config.IRC.RemoteNickFormat, "{NICK}", message.Username, -1)
|
if b.Config.IRC.RemoteNickFormat != "" {
|
||||||
|
username = strings.Replace(b.Config.IRC.RemoteNickFormat, "{NICK}", message.Username, -1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cmds := strings.Fields(message.Text)
|
cmds := strings.Fields(message.Text)
|
||||||
// empty message
|
// empty message
|
||||||
|
@ -353,17 +416,27 @@ func (b *Bridge) handleMatter() {
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "!users":
|
case "!users":
|
||||||
flog.mm.Info("Received !users from ", message.Username)
|
flog.mm.Info("Received !users from ", message.Username)
|
||||||
b.i.SendRaw("NAMES " + b.getIRCChannel(message.Channel))
|
if b.Config.General.Irc {
|
||||||
|
b.i.SendRaw("NAMES " + b.getIRCChannel(message.Channel))
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
case "!gif":
|
case "!gif":
|
||||||
message.Text = b.giphyRandom(strings.Fields(strings.Replace(message.Text, "!gif ", "", 1)))
|
message.Text = b.giphyRandom(strings.Fields(strings.Replace(message.Text, "!gif ", "", 1)))
|
||||||
b.Send(b.ircNick, message.Text, b.getIRCChannel(message.Channel))
|
if b.Config.General.Irc {
|
||||||
|
b.Send(b.ircNick, message.Text, b.getIRCChannel(message.Channel))
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
texts := strings.Split(message.Text, "\n")
|
texts := strings.Split(message.Text, "\n")
|
||||||
for _, text := range texts {
|
for _, text := range texts {
|
||||||
flog.mm.Debug("Sending message from " + message.Username + " to " + message.Channel)
|
flog.mm.Debug("Sending message from " + message.Username + " to " + message.Channel)
|
||||||
b.i.Privmsg(b.getIRCChannel(message.Channel), username+text)
|
if b.Config.General.Irc {
|
||||||
|
b.i.Privmsg(b.getIRCChannel(message.Channel), username+text)
|
||||||
|
}
|
||||||
|
if b.Config.General.Xmpp {
|
||||||
|
b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: "testje@c.sw.be", Text: username + text})
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,8 +453,14 @@ func (b *Bridge) giphyRandom(query []string) string {
|
||||||
return res.Data.FixedHeightDownsampledURL
|
return res.Data.FixedHeightDownsampledURL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) getMMChannel(ircChannel string) string {
|
func (b *Bridge) getMMChannel(channel string) string {
|
||||||
mmChannel := b.ircMap[ircChannel]
|
var mmChannel string
|
||||||
|
if b.Config.General.Irc {
|
||||||
|
mmChannel = b.ircMap[channel]
|
||||||
|
}
|
||||||
|
if b.Config.General.Xmpp {
|
||||||
|
mmChannel = b.xmppMap[channel]
|
||||||
|
}
|
||||||
if b.kind == Legacy {
|
if b.kind == Legacy {
|
||||||
return mmChannel
|
return mmChannel
|
||||||
}
|
}
|
||||||
|
@ -405,3 +484,41 @@ func (b *Bridge) ignoreMessage(nick string, message string, protocol string) boo
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) xmppKeepAlive() {
|
||||||
|
go func() {
|
||||||
|
ticker := time.NewTicker(90 * time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
b.xc.Send(xmpp.Chat{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) handleXmpp() error {
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
b.Send(nick, v.Text, b.getMMChannel(channel))
|
||||||
|
}
|
||||||
|
case xmpp.Presence:
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,12 +38,22 @@ type Config struct {
|
||||||
IgnoreNicks string
|
IgnoreNicks string
|
||||||
NoTLS bool
|
NoTLS bool
|
||||||
}
|
}
|
||||||
|
Xmpp struct {
|
||||||
|
Jid string
|
||||||
|
Password string
|
||||||
|
Server string
|
||||||
|
Muc string
|
||||||
|
Nick string
|
||||||
|
}
|
||||||
Channel map[string]*struct {
|
Channel map[string]*struct {
|
||||||
IRC string
|
IRC string
|
||||||
Mattermost string
|
Mattermost string
|
||||||
|
Xmpp string
|
||||||
}
|
}
|
||||||
General struct {
|
General struct {
|
||||||
GiphyAPIKey string
|
GiphyAPIKey string
|
||||||
|
Xmpp bool
|
||||||
|
Irc bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,31 @@ RemoteNickFormat="{NICK}: "
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
IgnoreNicks="ircspammer1 ircspammer2"
|
IgnoreNicks="ircspammer1 ircspammer2"
|
||||||
|
|
||||||
|
###################################################################
|
||||||
|
#XMPP section
|
||||||
|
###################################################################
|
||||||
|
[XMPP]
|
||||||
|
#xmpp server to connect to.
|
||||||
|
#REQUIRED
|
||||||
|
Server="jabber.example.com:5222"
|
||||||
|
|
||||||
|
#Jid
|
||||||
|
#REQUIRED
|
||||||
|
Jid="user@example.com"
|
||||||
|
|
||||||
|
#Password
|
||||||
|
#REQUIRED
|
||||||
|
Password="yourpass"
|
||||||
|
|
||||||
|
#MUC
|
||||||
|
#REQUIRED
|
||||||
|
Muc="conference.jabber.example.com"
|
||||||
|
|
||||||
|
#Your nick in the rooms
|
||||||
|
#REQUIRED
|
||||||
|
Nick="xmppbot"
|
||||||
|
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
#mattermost section
|
#mattermost section
|
||||||
###################################################################
|
###################################################################
|
||||||
|
@ -146,3 +171,8 @@ mattermost="testing"
|
||||||
#request your API key on https://github.com/giphy/GiphyAPI. This is a public beta key.
|
#request your API key on https://github.com/giphy/GiphyAPI. This is a public beta key.
|
||||||
#OPTIONAL
|
#OPTIONAL
|
||||||
GiphyApiKey="dc6zaTOxFJmzC"
|
GiphyApiKey="dc6zaTOxFJmzC"
|
||||||
|
|
||||||
|
#Choose only one protocol to bridge, do not set both to true!
|
||||||
|
#REQUIRED
|
||||||
|
Irc=true
|
||||||
|
Xmpp=false
|
||||||
|
|
Loading…
Reference in New Issue