diff options
author | Wim <wim@42.be> | 2016-09-18 19:21:15 +0200 |
---|---|---|
committer | Wim <wim@42.be> | 2016-09-18 19:21:15 +0200 |
commit | 7baf386edea4c71919b257d99ca7f7e07897c412 (patch) | |
tree | 5a6f7f0f506c3ab2d15d91548b1d0479bb8fb1ba /bridge | |
parent | 6e410b096ef15e976f6a2d28f3412fe9e457f95a (diff) | |
download | matterbridge-msglm-7baf386edea4c71919b257d99ca7f7e07897c412.tar.gz matterbridge-msglm-7baf386edea4c71919b257d99ca7f7e07897c412.tar.bz2 matterbridge-msglm-7baf386edea4c71919b257d99ca7f7e07897c412.zip |
Refactor for more flexibility
* Move from gcfg to toml configuration because gcfg was too restrictive
* Implemented gateway which has support multiple in and out bridges.
* Allow for bridging the same bridges, which means eg you can now bridge between multiple mattermosts.
* Support multiple gateways
Diffstat (limited to 'bridge')
-rw-r--r-- | bridge/bridge.go | 147 | ||||
-rw-r--r-- | bridge/config/config.go | 144 | ||||
-rw-r--r-- | bridge/gitter/gitter.go | 95 | ||||
-rw-r--r-- | bridge/irc/irc.go | 144 | ||||
-rw-r--r-- | bridge/mattermost/mattermost.go | 77 | ||||
-rw-r--r-- | bridge/slack/slack.go | 79 | ||||
-rw-r--r-- | bridge/xmpp/xmpp.go | 78 |
7 files changed, 351 insertions, 413 deletions
diff --git a/bridge/bridge.go b/bridge/bridge.go index 45a0160a..719af4fb 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -1,151 +1,40 @@ package bridge import ( - //"fmt" "github.com/42wim/matterbridge/bridge/config" "github.com/42wim/matterbridge/bridge/gitter" "github.com/42wim/matterbridge/bridge/irc" "github.com/42wim/matterbridge/bridge/mattermost" "github.com/42wim/matterbridge/bridge/slack" "github.com/42wim/matterbridge/bridge/xmpp" - log "github.com/Sirupsen/logrus" "strings" ) -type Bridge struct { - *config.Config - Source string - Bridges []Bridger - Channels []map[string]string - ignoreNicks map[string][]string -} - -type Bridger interface { +type Bridge interface { Send(msg config.Message) error Name() string Connect() error - //Command(cmd string) string -} - -func NewBridge(cfg *config.Config) error { - c := make(chan config.Message) - b := &Bridge{} - b.Config = cfg - if cfg.IRC.Enable { - b.Bridges = append(b.Bridges, birc.New(cfg, c)) - } - if cfg.Mattermost.Enable { - b.Bridges = append(b.Bridges, bmattermost.New(cfg, c)) - } - if cfg.Xmpp.Enable { - b.Bridges = append(b.Bridges, bxmpp.New(cfg, c)) - } - if cfg.Gitter.Enable { - b.Bridges = append(b.Bridges, bgitter.New(cfg, c)) - } - if cfg.Slack.Enable { - b.Bridges = append(b.Bridges, bslack.New(cfg, c)) - } - if len(b.Bridges) < 2 { - log.Fatalf("only %d sections enabled. Need at least 2 sections enabled (eg [IRC] and [mattermost]", len(b.Bridges)) - } - for _, br := range b.Bridges { - br.Connect() - } - b.mapChannels() - b.mapIgnores() - b.handleReceive(c) - return nil -} - -func (b *Bridge) handleReceive(c chan config.Message) { - for { - select { - case msg := <-c: - for _, br := range b.Bridges { - b.handleMessage(msg, br) - } - } - } + FullOrigin() string + Origin() string + Protocol() string + JoinChannel(channel string) error } -func (b *Bridge) mapChannels() error { - for _, val := range b.Config.Channel { - m := make(map[string]string) - m["irc"] = val.IRC - m["mattermost"] = val.Mattermost - m["xmpp"] = val.Xmpp - m["gitter"] = val.Gitter - m["slack"] = val.Slack - b.Channels = append(b.Channels, m) - } - return nil -} - -func (b *Bridge) mapIgnores() { - m := make(map[string][]string) - m["irc"] = strings.Fields(b.Config.IRC.IgnoreNicks) - m["mattermost"] = strings.Fields(b.Config.Mattermost.IgnoreNicks) - m["xmpp"] = strings.Fields(b.Config.Xmpp.IgnoreNicks) - m["gitter"] = strings.Fields(b.Config.Gitter.IgnoreNicks) - m["slack"] = strings.Fields(b.Config.Slack.IgnoreNicks) - b.ignoreNicks = m -} - -func (b *Bridge) getDestChannel(msg *config.Message, dest string) string { - for _, v := range b.Channels { - if v[msg.Origin] == msg.Channel { - return v[dest] - } - } - return "" -} - -func (b *Bridge) handleMessage(msg config.Message, dest Bridger) { - if b.ignoreMessage(&msg) { - return - } - if dest.Name() != msg.Origin { - msg.Channel = b.getDestChannel(&msg, dest.Name()) - if msg.Channel == "" { - return - } - b.modifyMessage(&msg, dest.Name()) - log.Debugf("sending %#v from %s to %s", msg, msg.Origin, dest.Name()) - dest.Send(msg) - } -} - -func (b *Bridge) ignoreMessage(msg *config.Message) bool { - // should we discard messages ? - for _, entry := range b.ignoreNicks[msg.Origin] { - if msg.Username == entry { - return true - } - } - return false -} - -func setNickFormat(msg *config.Message, format string) { - if format == "" { - msg.Username = msg.Origin + "-" + msg.Username + ": " - return - } - msg.Username = strings.Replace(format, "{NICK}", msg.Username, -1) - msg.Username = strings.Replace(msg.Username, "{BRIDGE}", msg.Origin, -1) -} - -func (b *Bridge) modifyMessage(msg *config.Message, dest string) { - switch dest { +func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) Bridge { + accInfo := strings.Split(bridge.Account, ".") + protocol := accInfo[0] + name := accInfo[1] + switch protocol { + case "mattermost": + return bmattermost.New(cfg.Mattermost[name], name, c) case "irc": - setNickFormat(msg, b.Config.IRC.RemoteNickFormat) + return birc.New(cfg.IRC[name], name, c) case "gitter": - setNickFormat(msg, b.Config.Gitter.RemoteNickFormat) - case "xmpp": - setNickFormat(msg, b.Config.Xmpp.RemoteNickFormat) - case "mattermost": - setNickFormat(msg, b.Config.Mattermost.RemoteNickFormat) + return bgitter.New(cfg.Gitter[name], name, c) case "slack": - setNickFormat(msg, b.Config.Slack.RemoteNickFormat) + return bslack.New(cfg.Slack[name], name, c) + case "xmpp": + return bxmpp.New(cfg.Xmpp[name], name, c) } + return nil } diff --git a/bridge/config/config.go b/bridge/config/config.go index 48574e28..ad8a523e 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -1,107 +1,73 @@ package config import ( - "gopkg.in/gcfg.v1" - "io/ioutil" + "github.com/BurntSushi/toml" "log" ) type Message struct { - Text string - Channel string - Username string - Origin string + Text string + Channel string + Username string + Origin string + FullOrigin string + Protocol string +} + +type Protocol struct { + BindAddress string // mattermost, slack + IconURL string // mattermost, slack + IgnoreNicks string // all protocols + Jid string // xmpp + Login string // mattermost + Muc string // xmpp + Name string // all protocols + Nick string // all protocols + NickFormatter string // mattermost, slack + NickServNick string // IRC + NickServPassword string // IRC + NicksPerRow int // mattermost, slack + NoTLS bool // mattermost + Password string // IRC,mattermost,XMPP + PrefixMessagesWithNick bool // mattemost, slack + Protocol string //all protocols + RemoteNickFormat string // all protocols + Server string // IRC,mattermost,XMPP + ShowJoinPart bool // all protocols + SkipTLSVerify bool // IRC, mattermost + Team string // mattermost + Token string // gitter, slack + URL string // mattermost, slack + UseAPI bool // mattermost, slack + UseSASL bool // IRC + UseTLS bool // IRC +} + +type Bridge struct { + Account string + Channel string +} + +type Gateway struct { + Name string + Enable bool + In []Bridge + Out []Bridge } type Config struct { - IRC struct { - UseTLS bool - UseSASL bool - SkipTLSVerify bool - Server string - Nick string - Password string - Channel string - NickServNick string - NickServPassword string - RemoteNickFormat string - IgnoreNicks string - Enable bool - } - Gitter struct { - Enable bool - IgnoreNicks string - Nick string - RemoteNickFormat string - Token string - } - Mattermost struct { - URL string - ShowJoinPart bool - IconURL string - SkipTLSVerify bool - BindAddress string - Channel string - PrefixMessagesWithNick bool - NicksPerRow int - NickFormatter string - Server string - Team string - Login string - Password string - RemoteNickFormat string - IgnoreNicks string - NoTLS bool - Enable bool - } - Slack struct { - BindAddress string - Enable bool - IconURL string - IgnoreNicks string - NickFormatter string - NicksPerRow int - PrefixMessagesWithNick bool - RemoteNickFormat string - Token string - URL string - UseAPI bool - } - Xmpp struct { - IgnoreNicks string - Jid string - Password string - Server string - Muc string - Nick string - RemoteNickFormat string - Enable bool - } - Channel map[string]*struct { - IRC string - Mattermost string - Xmpp string - Gitter string - Slack string - } - General struct { - GiphyAPIKey string - Xmpp bool - Irc bool - Mattermost bool - Plus bool - } + IRC map[string]Protocol + Mattermost map[string]Protocol + Slack map[string]Protocol + Gitter map[string]Protocol + Xmpp map[string]Protocol + Gateway []Gateway } func NewConfig(cfgfile string) *Config { var cfg Config - content, err := ioutil.ReadFile(cfgfile) - if err != nil { + if _, err := toml.DecodeFile("matterbridge.toml", &cfg); err != nil { log.Fatal(err) } - err = gcfg.ReadStringInto(&cfg, string(content)) - if err != nil { - log.Fatal("Failed to parse "+cfgfile+":", err) - } return &cfg } diff --git a/bridge/gitter/gitter.go b/bridge/gitter/gitter.go index 1d1b0a59..b00970d4 100644 --- a/bridge/gitter/gitter.go +++ b/bridge/gitter/gitter.go @@ -8,48 +8,91 @@ import ( ) type Bgitter struct { - c *gitter.Gitter - *config.Config - Remote chan config.Message - Rooms []gitter.Room -} - -type Message struct { - Text string - Channel string - Username string + c *gitter.Gitter + Config *config.Protocol + Remote chan config.Message + protocol string + origin string + Rooms []gitter.Room } var flog *log.Entry +var protocol = "gitter" func init() { - flog = log.WithFields(log.Fields{"module": "gitter"}) + flog = log.WithFields(log.Fields{"module": protocol}) } -func New(config *config.Config, c chan config.Message) *Bgitter { +func New(config config.Protocol, origin string, c chan config.Message) *Bgitter { b := &Bgitter{} - b.Config = config + b.Config = &config b.Remote = c + b.protocol = protocol + b.origin = origin return b } func (b *Bgitter) Connect() error { var err error - flog.Info("Trying Gitter connection") - b.c = gitter.New(b.Config.Gitter.Token) + flog.Info("Trying " + b.protocol + " connection") + b.c = gitter.New(b.Config.Token) _, err = b.c.GetUser() if err != nil { flog.Debugf("%#v", err) return err } flog.Info("Connection succeeded") - b.setupChannels() - go b.handleGitter() + //b.setupChannels() + b.Rooms, _ = b.c.GetRooms() + //go b.handleGitter() + return nil +} + +func (b *Bgitter) FullOrigin() string { + return b.protocol + "." + b.origin +} + +func (b *Bgitter) JoinChannel(channel string) error { + _, err := b.c.JoinRoom(channel) + if err != nil { + return err + } + room := channel + roomID := b.getRoomID(room) + if roomID == "" { + return nil + } + stream := b.c.Stream(roomID) + go b.c.Listen(stream) + + go func(stream *gitter.Stream, room string) { + for { + event := <-stream.Event + switch ev := event.Data.(type) { + case *gitter.MessageReceived: + // check for ZWSP to see if it's not an echo + if !strings.HasSuffix(ev.Message.Text, "") { + b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room, + Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} + } + case *gitter.GitterConnectionClosed: + flog.Errorf("connection with gitter closed for room %s", room) + } + } + }(stream, room) return nil } func (b *Bgitter) Name() string { - return "gitter" + return b.protocol + "." + b.origin +} + +func (b *Bgitter) Protocol() string { + return b.protocol +} + +func (b *Bgitter) Origin() string { + return b.origin } func (b *Bgitter) Send(msg config.Message) error { @@ -71,6 +114,7 @@ func (b *Bgitter) getRoomID(channel string) string { return "" } +/* func (b *Bgitter) handleGitter() { for _, val := range b.Config.Channel { room := val.Gitter @@ -88,7 +132,8 @@ func (b *Bgitter) handleGitter() { case *gitter.MessageReceived: // check for ZWSP to see if it's not an echo if !strings.HasSuffix(ev.Message.Text, "") { - b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room, Origin: "gitter"} + b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room, + Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} } case *gitter.GitterConnectionClosed: flog.Errorf("connection with gitter closed for room %s", room) @@ -97,14 +142,4 @@ func (b *Bgitter) handleGitter() { }(stream, room) } } - -func (b *Bgitter) setupChannels() { - b.Rooms, _ = b.c.GetRooms() - for _, val := range b.Config.Channel { - flog.Infof("Joining %s as %s", val.Gitter, b.Gitter.Nick) - _, err := b.c.JoinRoom(val.Gitter) - if err != nil { - log.Errorf("Joining %s failed", val.Gitter) - } - } -} +*/ diff --git a/bridge/irc/irc.go b/bridge/irc/irc.go index 102efa56..cb70732f 100644 --- a/bridge/irc/irc.go +++ b/bridge/irc/irc.go @@ -12,35 +12,32 @@ import ( "time" ) -//type Bridge struct { type Birc struct { - i *irc.Connection - ircNick string - ircMap map[string]string - names map[string][]string - ircIgnoreNicks []string - *config.Config - Remote chan config.Message + i *irc.Connection + ircNick string + name string + names map[string][]string + Config *config.Protocol + origin string + protocol string + Remote chan config.Message } -type FancyLog struct { - irc *log.Entry -} - -var flog FancyLog +var flog *log.Entry +var protocol = "irc" func init() { - flog.irc = log.WithFields(log.Fields{"module": "irc"}) + flog = log.WithFields(log.Fields{"module": protocol}) } -func New(config *config.Config, c chan config.Message) *Birc { +func New(config config.Protocol, origin string, c chan config.Message) *Birc { b := &Birc{} - b.Config = config + b.Config = &config b.Remote = c - b.ircNick = b.Config.IRC.Nick - b.ircMap = make(map[string]string) + b.protocol = protocol + b.ircNick = b.Config.Nick + b.origin = origin b.names = make(map[string][]string) - b.ircIgnoreNicks = strings.Fields(b.Config.IRC.IgnoreNicks) return b } @@ -53,32 +50,49 @@ func (b *Birc) Command(msg *config.Message) string { } func (b *Birc) Connect() error { - flog.irc.Info("Trying IRC connection") - i := irc.IRC(b.Config.IRC.Nick, b.Config.IRC.Nick) - i.UseTLS = b.Config.IRC.UseTLS - i.UseSASL = b.Config.IRC.UseSASL - i.SASLLogin = b.Config.IRC.NickServNick - i.SASLPassword = b.Config.IRC.NickServPassword - i.TLSConfig = &tls.Config{InsecureSkipVerify: b.Config.IRC.SkipTLSVerify} - if b.Config.IRC.Password != "" { - i.Password = b.Config.IRC.Password + flog.Info("Trying IRC connection") + i := irc.IRC(b.Config.Nick, b.Config.Nick) + i.UseTLS = b.Config.UseTLS + i.UseSASL = b.Config.UseSASL + i.SASLLogin = b.Config.NickServNick + i.SASLPassword = b.Config.NickServPassword + i.TLSConfig = &tls.Config{InsecureSkipVerify: b.Config.SkipTLSVerify} + if b.Config.Password != "" { + i.Password = b.Config.Password } i.AddCallback(ircm.RPL_WELCOME, b.handleNewConnection) - err := i.Connect(b.Config.IRC.Server) + err := i.Connect(b.Config.Server) if err != nil { return err } - flog.irc.Info("Connection succeeded") + flog.Info("Connection succeeded") b.i = i return nil } +func (b *Birc) FullOrigin() string { + return b.protocol + "." + b.origin +} + +func (b *Birc) JoinChannel(channel string) error { + b.i.Join(channel) + return nil +} + func (b *Birc) Name() string { - return "irc" + return b.protocol + "." + b.origin +} + +func (b *Birc) Protocol() string { + return b.protocol +} + +func (b *Birc) Origin() string { + return b.origin } func (b *Birc) Send(msg config.Message) error { - if msg.Origin == "irc" { + if msg.FullOrigin == b.FullOrigin() { return nil } if strings.HasPrefix(msg.Text, "!") { @@ -95,16 +109,18 @@ func (b *Birc) endNames(event *irc.Event) { maxNamesPerPost := (300 / b.nicksPerRow()) * b.nicksPerRow() continued := false for len(b.names[channel]) > maxNamesPerPost { - b.Remote <- config.Message{Username: b.ircNick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost], continued), Channel: channel, Origin: "irc"} + b.Remote <- config.Message{Username: b.ircNick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost], continued), + Channel: channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} b.names[channel] = b.names[channel][maxNamesPerPost:] continued = true } - b.Remote <- config.Message{Username: b.ircNick, Text: b.formatnicks(b.names[channel], continued), Channel: channel, Origin: "irc"} + b.Remote <- config.Message{Username: b.ircNick, Text: b.formatnicks(b.names[channel], continued), Channel: channel, + Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} b.names[channel] = nil } func (b *Birc) handleNewConnection(event *irc.Event) { - flog.irc.Info("Registering callbacks") + flog.Info("Registering callbacks") i := b.i b.ircNick = event.Arguments[0] i.AddCallback("PRIVMSG", b.handlePrivMsg) @@ -113,68 +129,55 @@ func (b *Birc) handleNewConnection(event *irc.Event) { i.AddCallback(ircm.RPL_ENDOFNAMES, b.endNames) i.AddCallback(ircm.RPL_NAMREPLY, b.storeNames) i.AddCallback(ircm.NOTICE, b.handleNotice) - i.AddCallback(ircm.RPL_MYINFO, func(e *irc.Event) { flog.irc.Infof("%s: %s", e.Code, strings.Join(e.Arguments[1:], " ")) }) + i.AddCallback(ircm.RPL_MYINFO, func(e *irc.Event) { flog.Infof("%s: %s", e.Code, strings.Join(e.Arguments[1:], " ")) }) i.AddCallback("PING", func(e *irc.Event) { i.SendRaw("PONG :" + e.Message()) - flog.irc.Debugf("PING/PONG") + flog.Debugf("PING/PONG") }) - if b.Config.Mattermost.ShowJoinPart { - i.AddCallback("JOIN", b.handleJoinPart) - i.AddCallback("PART", b.handleJoinPart) - } i.AddCallback("*", b.handleOther) - b.setupChannels() -} - -func (b *Birc) handleJoinPart(event *irc.Event) { - //b.Send(b.ircNick, b.ircNickFormat(event.Nick)+" "+strings.ToLower(event.Code)+"s "+event.Message(), b.getMMChannel(event.Arguments[0])) } func (b *Birc) handleNotice(event *irc.Event) { if strings.Contains(event.Message(), "This nickname is registered") { - b.i.Privmsg(b.Config.IRC.NickServNick, "IDENTIFY "+b.Config.IRC.NickServPassword) + b.i.Privmsg(b.Config.NickServNick, "IDENTIFY "+b.Config.NickServPassword) } } func (b *Birc) handleOther(event *irc.Event) { - flog.irc.Debugf("%#v", event) + flog.Debugf("%#v", event) } func (b *Birc) handlePrivMsg(event *irc.Event) { - flog.irc.Debugf("handlePrivMsg() %s %s", event.Nick, event.Message()) + flog.Debugf("handlePrivMsg() %s %s", event.Nick, event.Message()) msg := "" if event.Code == "CTCP_ACTION" { msg = event.Nick + " " } msg += event.Message() - b.Remote <- config.Message{Username: event.Nick, Text: msg, Channel: event.Arguments[0], Origin: "irc"} + b.Remote <- config.Message{Username: event.Nick, Text: msg, Channel: event.Arguments[0], Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} } func (b *Birc) handleTopicWhoTime(event *irc.Event) { parts := strings.Split(event.Arguments[2], "!") t, err := strconv.ParseInt(event.Arguments[3], 10, 64) if err != nil { - flog.irc.Errorf("Invalid time stamp: %s", event.Arguments[3]) + flog.Errorf("Invalid time stamp: %s", event.Arguments[3]) } user := parts[0] if len(parts) > 1 { user += " [" + parts[1] + "]" } - flog.irc.Infof("%s: Topic set by %s [%s]", event.Code, user, time.Unix(t, 0)) + flog.Infof("%s: Topic set by %s [%s]", event.Code, user, time.Unix(t, 0)) } func (b *Birc) nicksPerRow() int { - if b.Config.Mattermost.NicksPerRow < 1 { - return 4 - } - return b.Config.Mattermost.NicksPerRow -} - -func (b *Birc) setupChannels() { - for _, val := range b.Config.Channel { - flog.irc.Infof("Joining %s as %s", val.IRC, b.ircNick) - b.i.Join(val.IRC) - } + return 4 + /* + if b.Config.Mattermost.NicksPerRow < 1 { + return 4 + } + return b.Config.Mattermost.NicksPerRow + */ } func (b *Birc) storeNames(event *irc.Event) { @@ -185,10 +188,13 @@ func (b *Birc) storeNames(event *irc.Event) { } func (b *Birc) formatnicks(nicks []string, continued bool) string { - switch b.Config.Mattermost.NickFormatter { - case "table": - return tableformatter(nicks, b.nicksPerRow(), continued) - default: - return plainformatter(nicks, b.nicksPerRow()) - } + return plainformatter(nicks, b.nicksPerRow()) + /* + switch b.Config.Mattermost.NickFormatter { + case "table": + return tableformatter(nicks, b.nicksPerRow(), continued) + default: + return plainformatter(nicks, b.nicksPerRow()) + } + */ } diff --git a/bridge/mattermost/mattermost.go b/bridge/mattermost/mattermost.go index 6482b91b..7f560594 100644 --- a/bridge/mattermost/mattermost.go +++ b/bridge/mattermost/mattermost.go @@ -8,7 +8,6 @@ import ( "strings" ) -//type Bridge struct { type MMhook struct { mh *matterhook.Client } @@ -28,15 +27,16 @@ type MMMessage struct { type Bmattermost struct { MMhook MMapi - *config.Config - Plus bool - Remote chan config.Message + Config *config.Protocol + Plus bool + Remote chan config.Message + name string + origin string + protocol string } type FancyLog struct { - irc *log.Entry - mm *log.Entry - xmpp *log.Entry + mm *log.Entry } var flog FancyLog @@ -44,16 +44,17 @@ var flog FancyLog const Legacy = "legacy" func init() { - flog.irc = log.WithFields(log.Fields{"module": "irc"}) flog.mm = log.WithFields(log.Fields{"module": "mattermost"}) - flog.xmpp = log.WithFields(log.Fields{"module": "xmpp"}) } -func New(cfg *config.Config, c chan config.Message) *Bmattermost { +func New(cfg config.Protocol, origin string, c chan config.Message) *Bmattermost { b := &Bmattermost{} - b.Config = cfg + b.Config = &cfg + b.origin = origin b.Remote = c - b.Plus = cfg.General.Plus + b.protocol = "mattermost" + b.name = cfg.Name + b.Plus = cfg.UseAPI b.mmMap = make(map[string]string) return b } @@ -64,44 +65,62 @@ func (b *Bmattermost) Command(cmd string) string { func (b *Bmattermost) Connect() error { if !b.Plus { - b.mh = matterhook.New(b.Config.Mattermost.URL, - matterhook.Config{InsecureSkipVerify: b.Config.Mattermost.SkipTLSVerify, - BindAddress: b.Config.Mattermost.BindAddress}) + b.mh = matterhook.New(b.Config.URL, + matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, + BindAddress: b.Config.BindAddress}) } else { - b.mc = matterclient.New(b.Config.Mattermost.Login, b.Config.Mattermost.Password, - b.Config.Mattermost.Team, b.Config.Mattermost.Server) - b.mc.SkipTLSVerify = b.Config.Mattermost.SkipTLSVerify - b.mc.NoTLS = b.Config.Mattermost.NoTLS - flog.mm.Infof("Trying login %s (team: %s) on %s", b.Config.Mattermost.Login, b.Config.Mattermost.Team, b.Config.Mattermost.Server) + b.mc = matterclient.New(b.Config.Login, b.Config.Password, + b.Config.Team, b.Config.Server) + b.mc.SkipTLSVerify = b.Config.SkipTLSVerify + b.mc.NoTLS = b.Config.NoTLS + flog.mm.Infof("Trying login %s (team: %s) on %s", b.Config.Login, b.Config.Team, b.Config.Server) err := b.mc.Login() if err != nil { return err } flog.mm.Info("Login ok") - b.mc.JoinChannel(b.Config.Mattermost.Channel) - for _, val := range b.Config.Channel { - b.mc.JoinChannel(val.Mattermost) - } + /* + b.mc.JoinChannel(b.Config.Channel) + for _, val := range b.Config.Channel { + b.mc.JoinChannel(val.Mattermost) + } + */ go b.mc.WsReceiver() } go b.handleMatter() return nil } +func (b *Bmattermost) FullOrigin() string { + return b.protocol + "." + b.origin +} + +func (b *Bmattermost) JoinChannel(channel string) error { + return b.mc.JoinChannel(channel) +} + func (b *Bmattermost) Name() string { - return "mattermost" + return b.protocol + "." + b.origin +} + +func (b *Bmattermost) Origin() string { + return b.origin +} + +func (b *Bmattermost) Protocol() string { + return b.protocol } func (b *Bmattermost) Send(msg config.Message) error { flog.mm.Infof("mattermost send %#v", msg) - if msg.Origin != "mattermost" { + if msg.Origin != b.origin { return b.SendType(msg.Username, msg.Text, msg.Channel, "") } return nil } func (b *Bmattermost) SendType(nick string, message string, channel string, mtype string) error { - if b.Config.Mattermost.PrefixMessagesWithNick { + if b.Config.PrefixMessagesWithNick { /*if IsMarkup(message) { message = nick + "\n\n" + message } else { @@ -110,7 +129,7 @@ func (b *Bmattermost) SendType(nick string, message string, channel string, mtyp //} } if !b.Plus { - matterMessage := matterhook.OMessage{IconURL: b.Config.Mattermost.IconURL} + matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} matterMessage.Channel = channel matterMessage.UserName = nick matterMessage.Type = mtype @@ -141,7 +160,7 @@ func (b *Bmattermost) handleMatter() { texts := strings.Split(message.Text, "\n") for _, text := range texts { flog.mm.Debug("Sending message from " + message.Username + " to " + message.Channel) - b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Origin: "mattermost"} + b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} } } } diff --git a/bridge/slack/slack.go b/bridge/slack/slack.go index 804eaea4..fbaff703 100644 --- a/bridge/slack/slack.go +++ b/bridge/slack/slack.go @@ -15,41 +15,46 @@ type MMMessage struct { Username string } -type bslack struct { +type Bslack struct { mh *matterhook.Client sc *slack.Client // MMapi - *config.Config + Config *config.Protocol rtm *slack.RTM Plus bool Remote chan config.Message + protocol string + origin string channels []slack.Channel } var flog *log.Entry +var protocol = "slack" func init() { - flog = log.WithFields(log.Fields{"module": "slack"}) + flog = log.WithFields(log.Fields{"module": protocol}) } -func New(cfg *config.Config, c chan config.Message) *bslack { - b := &bslack{} - b.Config = cfg +func New(config config.Protocol, origin string, c chan config.Message) *Bslack { + b := &Bslack{} + b.Config = &config b.Remote = c - b.Plus = cfg.Slack.UseAPI + b.protocol = protocol + b.origin = origin + b.Plus = config.UseAPI return b } -func (b *bslack) Command(cmd string) string { +func (b *Bslack) Command(cmd string) string { return "" } -func (b *bslack) Connect() error { +func (b *Bslack) Connect() error { if !b.Plus { - b.mh = matterhook.New(b.Config.Slack.URL, - matterhook.Config{BindAddress: b.Config.Slack.BindAddress}) + b.mh = matterhook.New(b.Config.URL, + matterhook.Config{BindAddress: b.Config.BindAddress}) } else { - b.sc = slack.New(b.Config.Slack.Token) + b.sc = slack.New(b.Config.Token) flog.Infof("Trying login on slack with Token") /* if err != nil { @@ -64,11 +69,32 @@ func (b *bslack) Connect() error { return nil } -func (b *bslack) Name() string { - return "slack" +func (b *Bslack) FullOrigin() string { + return b.protocol + "." + b.origin } -func (b *bslack) Send(msg config.Message) error { +func (b *Bslack) JoinChannel(channel string) error { + schannel := b.getChannelByName(channel) + if schannel != nil && !schannel.IsMember { + flog.Infof("Joining %s", channel) + b.sc.JoinChannel(schannel.ID) + } + return nil +} + +func (b *Bslack) Name() string { + return b.protocol + "." + b.origin +} + +func (b *Bslack) Protocol() string { + return b.protocol +} + +func (b *Bslack) Origin() string { + return b.origin +} + +func (b *Bslack) Send(msg config.Message) error { flog.Infof("slack send %#v", msg) if msg.Origin != "slack" { return b.SendType(msg.Username, msg.Text, msg.Channel, "") @@ -76,12 +102,12 @@ func (b *bslack) Send(msg config.Message) error { return nil } -func (b *bslack) SendType(nick string, message string, channel string, mtype string) error { - if b.Config.Slack.PrefixMessagesWithNick { +func (b *Bslack) SendType(nick string, message string, channel string, mtype string) error { + if b.Config.PrefixMessagesWithNick { message = nick + " " + message } if !b.Plus { - matterMessage := matterhook.OMessage{IconURL: b.Config.Slack.IconURL} + matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} matterMessage.Channel = channel matterMessage.UserName = nick matterMessage.Type = mtype @@ -100,7 +126,7 @@ func (b *bslack) SendType(nick string, message string, channel string, mtype str return nil } -func (b *bslack) getChannelByName(name string) *slack.Channel { +func (b *Bslack) getChannelByName(name string) *slack.Channel { if b.channels == nil { return nil } @@ -112,7 +138,7 @@ func (b *bslack) getChannelByName(name string) *slack.Channel { return nil } -func (b *bslack) handleSlack() { +func (b *Bslack) handleSlack() { flog.Infof("Choosing API based slack connection: %t", b.Plus) mchan := make(chan *MMMessage) if b.Plus { @@ -126,12 +152,12 @@ func (b *bslack) handleSlack() { texts := strings.Split(message.Text, "\n") for _, text := range texts { flog.Debug("Sending message from " + message.Username + " to " + message.Channel) - b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Origin: "slack"} + b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} } } } -func (b *bslack) handleSlackClient(mchan chan *MMMessage) { +func (b *Bslack) handleSlackClient(mchan chan *MMMessage) { for msg := range b.rtm.IncomingEvents { switch ev := msg.Data.(type) { case *slack.MessageEvent: @@ -153,13 +179,6 @@ func (b *bslack) handleSlackClient(mchan chan *MMMessage) { flog.Debugf("%#v", ev.Error()) case *slack.ConnectedEvent: b.channels = ev.Info.Channels - for _, val := range b.Config.Channel { - channel := b.getChannelByName(val.Slack) - if channel != nil && !channel.IsMember { - flog.Infof("Joining %s", val.Slack) - b.sc.JoinChannel(channel.ID) - } - } case *slack.InvalidAuthEvent: flog.Fatalf("Invalid Token %#v", ev) default: @@ -167,7 +186,7 @@ func (b *bslack) handleSlackClient(mchan chan *MMMessage) { } } -func (b *bslack) handleMatterHook(mchan chan *MMMessage) { +func (b *Bslack) handleMatterHook(mchan chan *MMMessage) { for { message := b.mh.Receive() flog.Debugf("receiving from slack %#v", message) diff --git a/bridge/xmpp/xmpp.go b/bridge/xmpp/xmpp.go index 5d602475..3de95450 100644 --- a/bridge/xmpp/xmpp.go +++ b/bridge/xmpp/xmpp.go @@ -10,64 +10,75 @@ import ( ) type Bxmpp struct { - xc *xmpp.Client - xmppMap map[string]string - *config.Config - Remote chan config.Message + xc *xmpp.Client + xmppMap map[string]string + Config *config.Protocol + origin string + protocol string + Remote chan config.Message } -type FancyLog struct { - xmpp *log.Entry -} - -type Message struct { - Text string - Channel string - Username string -} - -var flog FancyLog +var flog *log.Entry +var protocol = "xmpp" func init() { - flog.xmpp = log.WithFields(log.Fields{"module": "xmpp"}) + flog = log.WithFields(log.Fields{"module": protocol}) } -func New(config *config.Config, c chan config.Message) *Bxmpp { +func New(config config.Protocol, origin string, c chan config.Message) *Bxmpp { b := &Bxmpp{} b.xmppMap = make(map[string]string) - b.Config = config + b.Config = &config + b.protocol = protocol + b.origin = origin b.Remote = c return b } func (b *Bxmpp) Connect() error { var err error - flog.xmpp.Info("Trying XMPP connection") + flog.Info("Trying XMPP connection") b.xc, err = b.createXMPP() if err != nil { - flog.xmpp.Debugf("%#v", err) + flog.Debugf("%#v", err) return err } - flog.xmpp.Info("Connection succeeded") - b.setupChannels() + flog.Info("Connection succeeded") go b.handleXmpp() return nil } +func (b *Bxmpp) FullOrigin() string { + return b.protocol + "." + b.origin +} + +func (b *Bxmpp) JoinChannel(channel string) error { + b.xc.JoinMUCNoHistory(channel+"@"+b.Config.Muc, b.Config.Nick) + return nil +} + func (b *Bxmpp) Name() string { - return "xmpp" + return b.protocol + "." + b.origin +} + +func (b *Bxmpp) Protocol() string { + return b.protocol +} + +func (b *Bxmpp) Origin() string { + return b.origin } func (b *Bxmpp) Send(msg config.Message) error { - b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Xmpp.Muc, Text: msg.Username + msg.Text}) + 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) { options := xmpp.Options{ - Host: b.Config.Xmpp.Server, - User: b.Config.Xmpp.Jid, - Password: b.Config.Xmpp.Password, + Host: b.Config.Server, + User: b.Config.Jid, + Password: b.Config.Password, NoTLS: true, StartTLS: true, //StartTLS: false, @@ -84,13 +95,6 @@ func (b *Bxmpp) createXMPP() (*xmpp.Client, error) { return b.xc, err } -func (b *Bxmpp) setupChannels() { - 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 *Bxmpp) xmppKeepAlive() { go func() { ticker := time.NewTicker(90 * time.Second) @@ -121,9 +125,9 @@ func (b *Bxmpp) handleXmpp() error { if len(s) == 2 { nick = s[1] } - if nick != b.Xmpp.Nick { - flog.xmpp.Infof("sending message to remote %s %s %s", nick, v.Text, channel) - b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Origin: "xmpp"} + if nick != b.Config.Nick { + flog.Infof("sending message to remote %s %s %s", nick, v.Text, channel) + b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} } } case xmpp.Presence: |