Merge branch 'refactor'

This commit is contained in:
Wim 2016-11-13 23:09:06 +01:00
commit 4976338677
11 changed files with 178 additions and 274 deletions

View File

@ -11,35 +11,50 @@ import (
"strings" "strings"
) )
type Bridge interface { type Bridger interface {
Send(msg config.Message) error Send(msg config.Message) error
Name() string
Connect() error Connect() error
FullOrigin() string
Origin() string
Protocol() string
JoinChannel(channel string) error JoinChannel(channel string) error
} }
func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) Bridge { type Bridge struct {
Config config.Protocol
Bridger
Name string
Account string
Protocol string
}
func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Bridge {
b := new(Bridge)
accInfo := strings.Split(bridge.Account, ".") accInfo := strings.Split(bridge.Account, ".")
protocol := accInfo[0] protocol := accInfo[0]
name := accInfo[1] name := accInfo[1]
b.Name = name
b.Protocol = protocol
b.Account = bridge.Account
// override config from environment // override config from environment
config.OverrideCfgFromEnv(cfg, protocol, name) config.OverrideCfgFromEnv(cfg, protocol, name)
switch protocol { switch protocol {
case "mattermost": case "mattermost":
return bmattermost.New(cfg.Mattermost[name], name, c) b.Config = cfg.Mattermost[name]
b.Bridger = bmattermost.New(cfg.Mattermost[name], bridge.Account, c)
case "irc": case "irc":
return birc.New(cfg.IRC[name], name, c) b.Config = cfg.IRC[name]
b.Bridger = birc.New(cfg.IRC[name], bridge.Account, c)
case "gitter": case "gitter":
return bgitter.New(cfg.Gitter[name], name, c) b.Config = cfg.Gitter[name]
b.Bridger = bgitter.New(cfg.Gitter[name], bridge.Account, c)
case "slack": case "slack":
return bslack.New(cfg.Slack[name], name, c) b.Config = cfg.Slack[name]
b.Bridger = bslack.New(cfg.Slack[name], bridge.Account, c)
case "xmpp": case "xmpp":
return bxmpp.New(cfg.Xmpp[name], name, c) b.Config = cfg.Xmpp[name]
b.Bridger = bxmpp.New(cfg.Xmpp[name], bridge.Account, c)
case "discord": case "discord":
return bdiscord.New(cfg.Discord[name], name, c) b.Config = cfg.Discord[name]
b.Bridger = bdiscord.New(cfg.Discord[name], bridge.Account, c)
} }
return nil return b
} }

View File

@ -12,10 +12,8 @@ type Message struct {
Text string Text string
Channel string Channel string
Username string Username string
Origin string
FullOrigin string
Protocol string
Avatar string Avatar string
Account string
} }
type Protocol struct { type Protocol struct {
@ -126,16 +124,11 @@ func OverrideCfgFromEnv(cfg *Config, protocol string, account string) {
func GetIconURL(msg *Message, cfg *Protocol) string { func GetIconURL(msg *Message, cfg *Protocol) string {
iconURL := cfg.IconURL iconURL := cfg.IconURL
info := strings.Split(msg.Account, ".")
protocol := info[0]
name := info[1]
iconURL = strings.Replace(iconURL, "{NICK}", msg.Username, -1) iconURL = strings.Replace(iconURL, "{NICK}", msg.Username, -1)
iconURL = strings.Replace(iconURL, "{BRIDGE}", msg.Origin, -1) iconURL = strings.Replace(iconURL, "{BRIDGE}", name, -1)
iconURL = strings.Replace(iconURL, "{PROTOCOL}", msg.Protocol, -1) iconURL = strings.Replace(iconURL, "{PROTOCOL}", protocol, -1)
return iconURL return iconURL
} }
func GetNick(msg *Message, cfg *Protocol) string {
nick := cfg.RemoteNickFormat
nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
nick = strings.Replace(nick, "{BRIDGE}", msg.Origin, -1)
nick = strings.Replace(nick, "{PROTOCOL}", msg.Protocol, -1)
return nick
}

View File

@ -11,8 +11,7 @@ type bdiscord struct {
c *discordgo.Session c *discordgo.Session
Config *config.Protocol Config *config.Protocol
Remote chan config.Message Remote chan config.Message
protocol string Account string
origin string
Channels []*discordgo.Channel Channels []*discordgo.Channel
Nick string Nick string
UseChannelID bool UseChannelID bool
@ -25,12 +24,11 @@ func init() {
flog = log.WithFields(log.Fields{"module": protocol}) flog = log.WithFields(log.Fields{"module": protocol})
} }
func New(cfg config.Protocol, origin string, c chan config.Message) *bdiscord { func New(cfg config.Protocol, account string, c chan config.Message) *bdiscord {
b := &bdiscord{} b := &bdiscord{}
b.Config = &cfg b.Config = &cfg
b.Remote = c b.Remote = c
b.protocol = protocol b.Account = account
b.origin = origin
return b return b
} }
@ -72,10 +70,6 @@ func (b *bdiscord) Connect() error {
return nil return nil
} }
func (b *bdiscord) FullOrigin() string {
return b.protocol + "." + b.origin
}
func (b *bdiscord) JoinChannel(channel string) error { func (b *bdiscord) JoinChannel(channel string) error {
idcheck := strings.Split(channel, "ID:") idcheck := strings.Split(channel, "ID:")
if len(idcheck) > 1 { if len(idcheck) > 1 {
@ -84,18 +78,6 @@ func (b *bdiscord) JoinChannel(channel string) error {
return nil return nil
} }
func (b *bdiscord) Name() string {
return b.protocol + "." + b.origin
}
func (b *bdiscord) Protocol() string {
return b.protocol
}
func (b *bdiscord) Origin() string {
return b.origin
}
func (b *bdiscord) Send(msg config.Message) error { func (b *bdiscord) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
channelID := b.getChannelID(msg.Channel) channelID := b.getChannelID(msg.Channel)
@ -103,8 +85,7 @@ func (b *bdiscord) Send(msg config.Message) error {
flog.Errorf("Could not find channelID for %v", msg.Channel) flog.Errorf("Could not find channelID for %v", msg.Channel)
return nil return nil
} }
nick := config.GetNick(&msg, b.Config) b.c.ChannelMessageSend(channelID, msg.Username+msg.Text)
b.c.ChannelMessageSend(channelID, nick+msg.Text)
return nil return nil
} }
@ -121,13 +102,13 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat
if m.Content == "" { if m.Content == "" {
return return
} }
flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.FullOrigin()) flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account)
channelName := b.getChannelName(m.ChannelID) channelName := b.getChannelName(m.ChannelID)
if b.UseChannelID { if b.UseChannelID {
channelName = "ID:" + m.ChannelID channelName = "ID:" + m.ChannelID
} }
b.Remote <- config.Message{Username: m.Author.Username, Text: m.ContentWithMentionsReplaced(), Channel: channelName, b.Remote <- config.Message{Username: m.Author.Username, Text: m.ContentWithMentionsReplaced(), Channel: channelName,
Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin(), Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"} Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg"}
} }
func (b *bdiscord) getChannelID(name string) string { func (b *bdiscord) getChannelID(name string) string {

View File

@ -11,8 +11,7 @@ type Bgitter struct {
c *gitter.Gitter c *gitter.Gitter
Config *config.Protocol Config *config.Protocol
Remote chan config.Message Remote chan config.Message
protocol string Account string
origin string
Users []gitter.User Users []gitter.User
Rooms []gitter.Room Rooms []gitter.Room
} }
@ -24,12 +23,11 @@ func init() {
flog = log.WithFields(log.Fields{"module": protocol}) flog = log.WithFields(log.Fields{"module": protocol})
} }
func New(cfg config.Protocol, origin string, c chan config.Message) *Bgitter { func New(cfg config.Protocol, account string, c chan config.Message) *Bgitter {
b := &Bgitter{} b := &Bgitter{}
b.Config = &cfg b.Config = &cfg
b.Remote = c b.Remote = c
b.protocol = protocol b.Account = account
b.origin = origin
return b return b
} }
@ -47,10 +45,6 @@ func (b *Bgitter) Connect() error {
return nil return nil
} }
func (b *Bgitter) FullOrigin() string {
return b.protocol + "." + b.origin
}
func (b *Bgitter) JoinChannel(channel string) error { func (b *Bgitter) JoinChannel(channel string) error {
room := channel room := channel
roomID := b.getRoomID(room) roomID := b.getRoomID(room)
@ -77,9 +71,9 @@ func (b *Bgitter) JoinChannel(channel string) error {
case *gitter.MessageReceived: case *gitter.MessageReceived:
// 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.FullOrigin()) 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, b.Remote <- config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room,
Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin(), Avatar: b.getAvatar(ev.Message.From.Username)} Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username)}
} }
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)
@ -89,18 +83,6 @@ func (b *Bgitter) JoinChannel(channel string) error {
return nil return nil
} }
func (b *Bgitter) Name() string {
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 { func (b *Bgitter) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
roomID := b.getRoomID(msg.Channel) roomID := b.getRoomID(msg.Channel)
@ -108,9 +90,8 @@ func (b *Bgitter) Send(msg config.Message) error {
flog.Errorf("Could not find roomID for %v", msg.Channel) flog.Errorf("Could not find roomID for %v", msg.Channel)
return nil return nil
} }
nick := config.GetNick(&msg, b.Config)
// add ZWSP because gitter echoes our own messages // add ZWSP because gitter echoes our own messages
return b.c.SendMessage(roomID, nick+msg.Text+" ") return b.c.SendMessage(roomID, msg.Username+msg.Text+" ")
} }
func (b *Bgitter) getRoomID(channel string) string { func (b *Bgitter) getRoomID(channel string) string {

View File

@ -19,11 +19,10 @@ type Birc struct {
Nick string Nick string
names map[string][]string names map[string][]string
Config *config.Protocol Config *config.Protocol
origin string
protocol string
Remote chan config.Message Remote chan config.Message
connected chan struct{} connected chan struct{}
Local chan config.Message // local queue for flood control Local chan config.Message // local queue for flood control
Account string
} }
var flog *log.Entry var flog *log.Entry
@ -33,14 +32,13 @@ func init() {
flog = log.WithFields(log.Fields{"module": protocol}) flog = log.WithFields(log.Fields{"module": protocol})
} }
func New(cfg config.Protocol, origin string, c chan config.Message) *Birc { func New(cfg config.Protocol, account string, c chan config.Message) *Birc {
b := &Birc{} b := &Birc{}
b.Config = &cfg b.Config = &cfg
b.Nick = b.Config.Nick b.Nick = b.Config.Nick
b.Remote = c b.Remote = c
b.names = make(map[string][]string) b.names = make(map[string][]string)
b.origin = origin b.Account = account
b.protocol = protocol
b.connected = make(chan struct{}) b.connected = make(chan struct{})
if b.Config.MessageDelay == 0 { if b.Config.MessageDelay == 0 {
b.Config.MessageDelay = 1300 b.Config.MessageDelay = 1300
@ -93,43 +91,26 @@ func (b *Birc) Connect() error {
return nil return nil
} }
func (b *Birc) FullOrigin() string {
return b.protocol + "." + b.origin
}
func (b *Birc) JoinChannel(channel string) error { func (b *Birc) JoinChannel(channel string) error {
b.i.Join(channel) b.i.Join(channel)
return nil return nil
} }
func (b *Birc) Name() string {
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 { func (b *Birc) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
if msg.FullOrigin == b.FullOrigin() { if msg.Account == b.Account {
return nil return nil
} }
if strings.HasPrefix(msg.Text, "!") { if strings.HasPrefix(msg.Text, "!") {
b.Command(&msg) b.Command(&msg)
return nil return nil
} }
nick := config.GetNick(&msg, b.Config)
for _, text := range strings.Split(msg.Text, "\n") { for _, text := range strings.Split(msg.Text, "\n") {
if len(b.Local) < b.Config.MessageQueue { if len(b.Local) < b.Config.MessageQueue {
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: nick, Channel: msg.Channel} b.Local <- config.Message{Text: text, Username: msg.Username, Channel: msg.Channel}
} else { } else {
flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local))
} }
@ -153,12 +134,12 @@ func (b *Birc) endNames(event *irc.Event) {
continued := false continued := false
for len(b.names[channel]) > maxNamesPerPost { for len(b.names[channel]) > maxNamesPerPost {
b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost], continued), b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel][0:maxNamesPerPost], continued),
Channel: channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} Channel: channel, Account: b.Account}
b.names[channel] = b.names[channel][maxNamesPerPost:] b.names[channel] = b.names[channel][maxNamesPerPost:]
continued = true continued = true
} }
b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel], continued), Channel: channel, b.Remote <- config.Message{Username: b.Nick, Text: b.formatnicks(b.names[channel], continued),
Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} Channel: channel, Account: b.Account}
b.names[channel] = nil b.names[channel] = nil
} }
@ -215,8 +196,8 @@ func (b *Birc) handlePrivMsg(event *irc.Event) {
// strip IRC colors // strip IRC colors
re := regexp.MustCompile(`[[:cntrl:]](\d+,|)\d+`) re := regexp.MustCompile(`[[:cntrl:]](\d+,|)\d+`)
msg = re.ReplaceAllString(msg, "") msg = re.ReplaceAllString(msg, "")
flog.Debugf("Sending message from %s on %s to gateway", event.Arguments[0], b.FullOrigin()) 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], Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} b.Remote <- config.Message{Username: event.Nick, Text: msg, Channel: event.Arguments[0], Account: b.Account}
} }
func (b *Birc) handleTopicWhoTime(event *irc.Event) { func (b *Birc) handleTopicWhoTime(event *irc.Event) {

View File

@ -29,9 +29,8 @@ type Bmattermost struct {
Config *config.Protocol Config *config.Protocol
Remote chan config.Message Remote chan config.Message
name string name string
origin string
protocol string
TeamId string TeamId string
Account string
} }
var flog *log.Entry var flog *log.Entry
@ -41,13 +40,11 @@ func init() {
flog = log.WithFields(log.Fields{"module": protocol}) flog = log.WithFields(log.Fields{"module": protocol})
} }
func New(cfg config.Protocol, origin string, c chan config.Message) *Bmattermost { func New(cfg config.Protocol, account string, c chan config.Message) *Bmattermost {
b := &Bmattermost{} b := &Bmattermost{}
b.Config = &cfg b.Config = &cfg
b.origin = origin
b.Remote = c b.Remote = c
b.protocol = "mattermost" b.Account = account
b.name = cfg.Name
b.mmMap = make(map[string]string) b.mmMap = make(map[string]string)
return b return b
} }
@ -80,10 +77,6 @@ func (b *Bmattermost) Connect() error {
return nil return nil
} }
func (b *Bmattermost) FullOrigin() string {
return b.protocol + "." + b.origin
}
func (b *Bmattermost) JoinChannel(channel string) error { func (b *Bmattermost) JoinChannel(channel string) error {
// we can only join channels using the API // we can only join channels using the API
if b.Config.UseAPI { if b.Config.UseAPI {
@ -92,21 +85,9 @@ func (b *Bmattermost) JoinChannel(channel string) error {
return nil return nil
} }
func (b *Bmattermost) Name() string {
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 { func (b *Bmattermost) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
nick := config.GetNick(&msg, b.Config) nick := msg.Username
message := msg.Text message := msg.Text
channel := msg.Channel channel := msg.Channel
@ -144,8 +125,8 @@ func (b *Bmattermost) handleMatter() {
go b.handleMatterHook(mchan) go b.handleMatterHook(mchan)
} }
for message := range mchan { for message := range mchan {
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.FullOrigin()) 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, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} b.Remote <- config.Message{Text: message.Text, Username: message.Username, Channel: message.Channel, Account: b.Account}
} }
} }

View File

@ -25,8 +25,7 @@ type Bslack struct {
Plus bool Plus bool
Remote chan config.Message Remote chan config.Message
Users []slack.User Users []slack.User
protocol string Account string
origin string
si *slack.Info si *slack.Info
channels []slack.Channel channels []slack.Channel
} }
@ -38,12 +37,11 @@ func init() {
flog = log.WithFields(log.Fields{"module": protocol}) flog = log.WithFields(log.Fields{"module": protocol})
} }
func New(cfg config.Protocol, origin string, c chan config.Message) *Bslack { func New(cfg config.Protocol, account string, c chan config.Message) *Bslack {
b := &Bslack{} b := &Bslack{}
b.Config = &cfg b.Config = &cfg
b.Remote = c b.Remote = c
b.protocol = protocol b.Account = account
b.origin = origin
return b return b
} }
@ -66,10 +64,6 @@ func (b *Bslack) Connect() error {
return nil return nil
} }
func (b *Bslack) FullOrigin() string {
return b.protocol + "." + b.origin
}
func (b *Bslack) JoinChannel(channel string) error { func (b *Bslack) JoinChannel(channel string) error {
// we can only join channels using the API // we can only join channels using the API
if b.Config.UseAPI { if b.Config.UseAPI {
@ -81,24 +75,12 @@ func (b *Bslack) JoinChannel(channel string) error {
return nil 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 { func (b *Bslack) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
if msg.FullOrigin == b.FullOrigin() { if msg.Account == b.Account {
return nil return nil
} }
nick := config.GetNick(&msg, b.Config) nick := msg.Username
message := msg.Text message := msg.Text
channel := msg.Channel channel := msg.Channel
if b.Config.PrefixMessagesWithNick { if b.Config.PrefixMessagesWithNick {
@ -154,14 +136,14 @@ func (b *Bslack) getAvatar(user string) string {
func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) { func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) {
if b.channels == nil { if b.channels == nil {
return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.FullOrigin(), name) return nil, fmt.Errorf("%s: channel %s not found (no channels found)", b.Account, name)
} }
for _, channel := range b.channels { for _, channel := range b.channels {
if channel.Name == name { if channel.Name == name {
return &channel, nil return &channel, nil
} }
} }
return nil, fmt.Errorf("%s: channel %s not found", b.FullOrigin(), name) return nil, fmt.Errorf("%s: channel %s not found", b.Account, name)
} }
func (b *Bslack) handleSlack() { func (b *Bslack) handleSlack() {
@ -181,8 +163,8 @@ func (b *Bslack) handleSlack() {
} }
texts := strings.Split(message.Text, "\n") texts := strings.Split(message.Text, "\n")
for _, text := range texts { for _, text := range texts {
flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.FullOrigin()) flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account)
b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin(), Avatar: b.getAvatar(message.Username)} b.Remote <- config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username)}
} }
} }
} }

View File

@ -13,9 +13,8 @@ type Bxmpp struct {
xc *xmpp.Client xc *xmpp.Client
xmppMap map[string]string xmppMap map[string]string
Config *config.Protocol Config *config.Protocol
origin string
protocol string
Remote chan config.Message Remote chan config.Message
Account string
} }
var flog *log.Entry var flog *log.Entry
@ -25,12 +24,11 @@ func init() {
flog = log.WithFields(log.Fields{"module": protocol}) flog = log.WithFields(log.Fields{"module": protocol})
} }
func New(cfg config.Protocol, origin string, c chan config.Message) *Bxmpp { func New(cfg config.Protocol, account string, c chan config.Message) *Bxmpp {
b := &Bxmpp{} b := &Bxmpp{}
b.xmppMap = make(map[string]string) b.xmppMap = make(map[string]string)
b.Config = &cfg b.Config = &cfg
b.protocol = protocol b.Account = account
b.origin = origin
b.Remote = c b.Remote = c
return b return b
} }
@ -48,31 +46,14 @@ func (b *Bxmpp) Connect() error {
return nil return nil
} }
func (b *Bxmpp) FullOrigin() string {
return b.protocol + "." + b.origin
}
func (b *Bxmpp) JoinChannel(channel string) error { func (b *Bxmpp) JoinChannel(channel string) error {
b.xc.JoinMUCNoHistory(channel+"@"+b.Config.Muc, b.Config.Nick) b.xc.JoinMUCNoHistory(channel+"@"+b.Config.Muc, b.Config.Nick)
return nil return nil
} }
func (b *Bxmpp) Name() string {
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 { func (b *Bxmpp) Send(msg config.Message) error {
flog.Debugf("Receiving %#v", msg) flog.Debugf("Receiving %#v", msg)
nick := config.GetNick(&msg, b.Config) b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text})
b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: nick + msg.Text})
return nil return nil
} }
@ -128,8 +109,8 @@ func (b *Bxmpp) handleXmpp() error {
nick = s[1] nick = s[1]
} }
if nick != b.Config.Nick { if nick != b.Config.Nick {
flog.Debugf("Sending message from %s on %s to gateway", nick, b.FullOrigin()) flog.Debugf("Sending message from %s on %s to gateway", nick, b.Account)
b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Origin: b.origin, Protocol: b.protocol, FullOrigin: b.FullOrigin()} b.Remote <- config.Message{Username: nick, Text: v.Text, Channel: channel, Account: b.Account}
} }
} }
case xmpp.Presence: case xmpp.Presence:

View File

@ -12,54 +12,67 @@ import (
type Gateway struct { type Gateway struct {
*config.Config *config.Config
MyConfig *config.Gateway MyConfig *config.Gateway
Bridges []bridge.Bridge //Bridges []*bridge.Bridge
Bridges map[string]*bridge.Bridge
ChannelsOut map[string][]string ChannelsOut map[string][]string
ChannelsIn map[string][]string ChannelsIn map[string][]string
ignoreNicks map[string][]string ignoreNicks map[string][]string
Name string Name string
Message chan config.Message
} }
func New(cfg *config.Config, gateway *config.Gateway) error { func New(cfg *config.Config, gateway *config.Gateway) *Gateway {
c := make(chan config.Message)
gw := &Gateway{} gw := &Gateway{}
gw.Name = gateway.Name gw.Name = gateway.Name
gw.Config = cfg gw.Config = cfg
gw.MyConfig = gateway gw.MyConfig = gateway
exists := make(map[string]bool) gw.Message = make(chan config.Message)
for _, br := range append(gateway.In, gateway.Out...) { gw.Bridges = make(map[string]*bridge.Bridge)
if exists[br.Account] { return gw
continue
} }
log.Infof("Starting bridge: %s channel: %s", br.Account, br.Channel)
gw.Bridges = append(gw.Bridges, bridge.New(cfg, &br, c)) func (gw *Gateway) AddBridge(cfg *config.Bridge) error {
exists[br.Account] = true
}
gw.mapChannels()
//TODO fix mapIgnores
//gw.mapIgnores()
exists = make(map[string]bool)
for _, br := range gw.Bridges { for _, br := range gw.Bridges {
if br.Account == cfg.Account {
return nil
}
}
log.Infof("Starting bridge: %s ", cfg.Account)
br := bridge.New(gw.Config, cfg, gw.Message)
gw.Bridges[cfg.Account] = br
err := br.Connect() err := br.Connect()
if err != nil { if err != nil {
log.Fatalf("Bridge %s failed to start: %v", br.FullOrigin(), err) return fmt.Errorf("Bridge %s failed to start: %v", br.Account, err)
} }
for _, channel := range append(gw.ChannelsOut[br.FullOrigin()], gw.ChannelsIn[br.FullOrigin()]...) { exists := make(map[string]bool)
if exists[br.FullOrigin()+channel] { for _, channel := range append(gw.ChannelsOut[br.Account], gw.ChannelsIn[br.Account]...) {
continue if !exists[br.Account+channel] {
} log.Infof("%s: joining %s", br.Account, channel)
log.Infof("%s: joining %s", br.FullOrigin(), channel)
br.JoinChannel(channel) br.JoinChannel(channel)
exists[br.FullOrigin()+channel] = true exists[br.Account+channel] = true
} }
} }
gw.handleReceive(c)
return nil return nil
} }
func (gw *Gateway) handleReceive(c chan config.Message) { func (gw *Gateway) Start() error {
gw.mapChannels()
for _, br := range append(gw.MyConfig.In, gw.MyConfig.Out...) {
err := gw.AddBridge(&br)
if err != nil {
return err
}
}
//TODO fix mapIgnores
//gw.mapIgnores()
go gw.handleReceive()
return nil
}
func (gw *Gateway) handleReceive() {
for { for {
select { select {
case msg := <-c: case msg := <-gw.Message:
for _, br := range gw.Bridges { for _, br := range gw.Bridges {
gw.handleMessage(msg, br) gw.handleMessage(msg, br)
} }
@ -92,7 +105,7 @@ func (gw *Gateway) mapIgnores() {
} }
func (gw *Gateway) getDestChannel(msg *config.Message, dest string) []string { func (gw *Gateway) getDestChannel(msg *config.Message, dest string) []string {
channels := gw.ChannelsIn[msg.FullOrigin] channels := gw.ChannelsIn[msg.Account]
for _, channel := range channels { for _, channel := range channels {
if channel == msg.Channel { if channel == msg.Channel {
return gw.ChannelsOut[dest] return gw.ChannelsOut[dest]
@ -101,15 +114,15 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest string) []string {
return []string{} return []string{}
} }
func (gw *Gateway) handleMessage(msg config.Message, dest bridge.Bridge) { func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
if gw.ignoreMessage(&msg) { if gw.ignoreMessage(&msg) {
return return
} }
originchannel := msg.Channel originchannel := msg.Channel
channels := gw.getDestChannel(&msg, dest.FullOrigin()) channels := gw.getDestChannel(&msg, dest.Account)
for _, channel := range channels { for _, channel := range channels {
// do not send the message to the bridge we come from if also the channel is the same // do not send the message to the bridge we come from if also the channel is the same
if msg.FullOrigin == dest.FullOrigin() && channel == originchannel { if msg.Account == dest.Account && channel == originchannel {
continue continue
} }
msg.Channel = channel msg.Channel = channel
@ -117,7 +130,8 @@ func (gw *Gateway) handleMessage(msg config.Message, dest bridge.Bridge) {
log.Debug("empty channel") log.Debug("empty channel")
return return
} }
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.FullOrigin, originchannel, dest.FullOrigin(), channel) log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel)
gw.modifyUsername(&msg, dest)
err := dest.Send(msg) err := dest.Send(msg)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
@ -127,7 +141,7 @@ func (gw *Gateway) handleMessage(msg config.Message, dest bridge.Bridge) {
func (gw *Gateway) ignoreMessage(msg *config.Message) bool { func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
// should we discard messages ? // should we discard messages ?
for _, entry := range gw.ignoreNicks[msg.FullOrigin] { for _, entry := range gw.ignoreNicks[msg.Account] {
if msg.Username == entry { if msg.Username == entry {
return true return true
} }
@ -135,17 +149,26 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
return false return false
} }
func (gw *Gateway) modifyMessage(msg *config.Message, dest bridge.Bridge) { func (gw *Gateway) modifyMessage(msg *config.Message, dest *bridge.Bridge) {
val := reflect.ValueOf(gw.Config).Elem() val := reflect.ValueOf(gw.Config).Elem()
for i := 0; i < val.NumField(); i++ { for i := 0; i < val.NumField(); i++ {
typeField := val.Type().Field(i) typeField := val.Type().Field(i)
// look for the protocol map (both lowercase) // look for the protocol map (both lowercase)
if strings.ToLower(typeField.Name) == dest.Protocol() { if strings.ToLower(typeField.Name) == dest.Protocol {
// get the Protocol struct from the map // get the Protocol struct from the map
protoCfg := val.Field(i).MapIndex(reflect.ValueOf(dest.Origin())) protoCfg := val.Field(i).MapIndex(reflect.ValueOf(dest.Name))
//config.SetNickFormat(msg, protoCfg.Interface().(config.Protocol)) //config.SetNickFormat(msg, protoCfg.Interface().(config.Protocol))
val.Field(i).SetMapIndex(reflect.ValueOf(dest.Origin()), protoCfg) val.Field(i).SetMapIndex(reflect.ValueOf(dest.Name), protoCfg)
break break
} }
} }
} }
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
br := gw.Bridges[msg.Account]
nick := dest.Config.RemoteNickFormat
nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
msg.Username = nick
}

View File

@ -10,7 +10,7 @@ import (
type SameChannelGateway struct { type SameChannelGateway struct {
*config.Config *config.Config
MyConfig *config.SameChannelGateway MyConfig *config.SameChannelGateway
Bridges []bridge.Bridge Bridges map[string]*bridge.Bridge
Channels []string Channels []string
ignoreNicks map[string][]string ignoreNicks map[string][]string
Name string Name string
@ -19,6 +19,7 @@ type SameChannelGateway struct {
func New(cfg *config.Config, gateway *config.SameChannelGateway) error { func New(cfg *config.Config, gateway *config.SameChannelGateway) error {
c := make(chan config.Message) c := make(chan config.Message)
gw := &SameChannelGateway{} gw := &SameChannelGateway{}
gw.Bridges = make(map[string]*bridge.Bridge)
gw.Name = gateway.Name gw.Name = gateway.Name
gw.Config = cfg gw.Config = cfg
gw.MyConfig = gateway gw.MyConfig = gateway
@ -26,15 +27,15 @@ func New(cfg *config.Config, gateway *config.SameChannelGateway) error {
for _, account := range gateway.Accounts { for _, account := range gateway.Accounts {
br := config.Bridge{Account: account} br := config.Bridge{Account: account}
log.Infof("Starting bridge: %s", account) log.Infof("Starting bridge: %s", account)
gw.Bridges = append(gw.Bridges, bridge.New(cfg, &br, c)) gw.Bridges[account] = bridge.New(cfg, &br, c)
} }
for _, br := range gw.Bridges { for _, br := range gw.Bridges {
err := br.Connect() err := br.Connect()
if err != nil { if err != nil {
log.Fatalf("Bridge %s failed to start: %v", br.FullOrigin(), err) log.Fatalf("Bridge %s failed to start: %v", br.Account, err)
} }
for _, channel := range gw.Channels { for _, channel := range gw.Channels {
log.Infof("%s: joining %s", br.FullOrigin(), channel) log.Infof("%s: joining %s", br.Account, channel)
br.JoinChannel(channel) br.JoinChannel(channel)
} }
} }
@ -59,38 +60,24 @@ func (gw *SameChannelGateway) handleMessage(msg config.Message, dest bridge.Brid
return return
} }
// do not send the message to the bridge we come from if also the channel is the same // do not send the message to the bridge we come from if also the channel is the same
if msg.FullOrigin == dest.FullOrigin() { if msg.Account == dest.Account {
return return
} }
gw.modifyMessage(&msg, dest) gw.modifyUsername(&msg, dest)
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.FullOrigin, msg.Channel, dest.FullOrigin(), msg.Channel) log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, msg.Channel, dest.Account, msg.Channel)
err := dest.Send(msg) err := dest.Send(msg)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
} }
} }
func setNickFormat(msg *config.Message, format string) { func (gw *SameChannelGateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
if format == "" { br := gw.Bridges[msg.Account]
msg.Username = msg.Protocol + "." + msg.Origin + "-" + msg.Username + ": " nick := dest.Config.RemoteNickFormat
return nick = strings.Replace(nick, "{NICK}", msg.Username, -1)
} nick = strings.Replace(nick, "{BRIDGE}", br.Name, -1)
msg.Username = strings.Replace(format, "{NICK}", msg.Username, -1) nick = strings.Replace(nick, "{PROTOCOL}", br.Protocol, -1)
msg.Username = strings.Replace(msg.Username, "{BRIDGE}", msg.Origin, -1) msg.Username = nick
msg.Username = strings.Replace(msg.Username, "{PROTOCOL}", msg.Protocol, -1)
}
func (gw *SameChannelGateway) modifyMessage(msg *config.Message, dest bridge.Bridge) {
switch dest.Protocol() {
case "irc":
setNickFormat(msg, gw.Config.IRC[dest.Origin()].RemoteNickFormat)
case "mattermost":
setNickFormat(msg, gw.Config.Mattermost[dest.Origin()].RemoteNickFormat)
case "slack":
setNickFormat(msg, gw.Config.Slack[dest.Origin()].RemoteNickFormat)
case "discord":
setNickFormat(msg, gw.Config.Discord[dest.Origin()].RemoteNickFormat)
}
} }
func (gw *SameChannelGateway) validChannel(channel string) bool { func (gw *SameChannelGateway) validChannel(channel string) bool {

View File

@ -49,12 +49,11 @@ func main() {
continue continue
} }
fmt.Printf("starting gateway %#v\n", gw.Name) fmt.Printf("starting gateway %#v\n", gw.Name)
go func(gw config.Gateway) { g := gateway.New(cfg, &gw)
err := gateway.New(cfg, &gw) err := g.Start()
if err != nil { if err != nil {
log.Debugf("starting gateway failed %#v", err) log.Debugf("starting gateway failed %#v", err)
} }
}(gw)
} }
select {} select {}
} }