mirror of
https://github.com/cwinfo/matterbridge.git
synced 2025-06-26 18:59:24 +00:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
22307b1934 | |||
bd97357f8d | |||
10dab1366e | |||
52fc94c1fe | |||
c1c7961dd6 | |||
d3eef051b1 | |||
57654df81e | |||
0f791d7a9a | |||
58779e0d65 | |||
4ac361b5fd |
115
README-0.6.md
115
README-0.6.md
@ -1,115 +0,0 @@
|
||||
# matterbridge
|
||||
|
||||
Simple bridge between mattermost, IRC, XMPP, Gitter and Slack
|
||||
|
||||
* Relays public channel messages between mattermost, IRC, XMPP, Gitter and Slack. Pick and mix.
|
||||
* Supports multiple channels.
|
||||
* Matterbridge can also work with private groups on your mattermost.
|
||||
|
||||
Look at [matterbridge.conf.sample] (https://github.com/42wim/matterbridge/blob/master/matterbridge.conf.sample) for documentation and an example.
|
||||
|
||||
## Changelog
|
||||
Since v0.6.1 support for XMPP, Gitter and Slack is added. More details in [changelog.md] (https://github.com/42wim/matterbridge/blob/master/changelog.md)
|
||||
|
||||
## Requirements:
|
||||
Accounts to one of the supported bridges
|
||||
* [Mattermost] (https://github.com/mattermost/platform/)
|
||||
* [IRC] (http://www.mirc.com/servers.html)
|
||||
* [XMPP] (https://jabber.org)
|
||||
* [Gitter] (https://gitter.im)
|
||||
* [Slack] (https://www.slack.com)
|
||||
|
||||
## binaries
|
||||
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
|
||||
* For use with mattermost 3.3.0+ [v0.6.1](https://github.com/42wim/matterircd/releases/tag/v0.6.1)
|
||||
* For use with mattermost 3.0.0-3.2.0 [v0.5.0](https://github.com/42wim/matterircd/releases/tag/v0.5.0)
|
||||
|
||||
|
||||
## Docker
|
||||
Create your matterbridge.conf file locally eg in ```/tmp/matterbridge.conf```
|
||||
|
||||
```
|
||||
docker run -ti -v /tmp/matterbridge.conf:/matterbridge.conf 42wim/matterbridge:0.6.1
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
### Mattermost
|
||||
* Matterbridge v0.6.1 works with mattermost 3.3.0 and higher [3.3.0 release](https://github.com/mattermost/platform/releases/tag/v3.3.0)
|
||||
* Matterbridge v0.5.0 works with mattermost 3.0.0 - 3.2.0 [3.2.0 release](https://github.com/mattermost/platform/releases/tag/v3.2.0)
|
||||
|
||||
|
||||
#### Webhooks version
|
||||
* Configured incoming/outgoing [webhooks](https://www.mattermost.org/webhooks/) on your mattermost instance.
|
||||
|
||||
#### Plus (API) version
|
||||
* A dedicated user(bot) on your mattermost instance.
|
||||
|
||||
|
||||
## building
|
||||
Go 1.6+ is required. Make sure you have [Go](https://golang.org/doc/install) properly installed, including setting up your [GOPATH] (https://golang.org/doc/code.html#GOPATH)
|
||||
|
||||
```
|
||||
cd $GOPATH
|
||||
go get github.com/42wim/matterbridge
|
||||
```
|
||||
|
||||
You should now have matterbridge binary in the bin directory:
|
||||
|
||||
```
|
||||
$ ls bin/
|
||||
matterbridge
|
||||
```
|
||||
|
||||
## running
|
||||
1) Copy the matterbridge.conf.sample to matterbridge.conf in the same directory as the matterbridge binary.
|
||||
2) Edit matterbridge.conf with the settings for your environment. See below for more config information.
|
||||
3) Now you can run matterbridge.
|
||||
|
||||
```
|
||||
Usage of ./matterbridge:
|
||||
-conf string
|
||||
config file (default "matterbridge.conf")
|
||||
-debug
|
||||
enable debug
|
||||
-plus
|
||||
running using API instead of webhooks (deprecated, set Plus flag in [general] config)
|
||||
-version
|
||||
show version
|
||||
```
|
||||
|
||||
## config
|
||||
### matterbridge
|
||||
matterbridge looks for matterbridge.conf in current directory. (use -conf to specify another file)
|
||||
|
||||
Look at [matterbridge.conf.sample] (https://github.com/42wim/matterbridge/blob/master/matterbridge.conf.sample) for an example.
|
||||
|
||||
### mattermost
|
||||
#### webhooks version
|
||||
You'll have to configure the incoming and outgoing webhooks.
|
||||
|
||||
* incoming webhooks
|
||||
Go to "account settings" - integrations - "incoming webhooks".
|
||||
Choose a channel at "Add a new incoming webhook", this will create a webhook URL right below.
|
||||
This URL should be set in the matterbridge.conf in the [mattermost] section (see above)
|
||||
|
||||
* outgoing webhooks
|
||||
Go to "account settings" - integrations - "outgoing webhooks".
|
||||
Choose a channel (the same as the one from incoming webhooks) and fill in the address and port of the server matterbridge will run on.
|
||||
|
||||
e.g. http://192.168.1.1:9999 (192.168.1.1:9999 is the BindAddress specified in [mattermost] section of matterbridge.conf)
|
||||
|
||||
#### plus version
|
||||
You'll have to create a new dedicated user on your mattermost instance.
|
||||
Specify the login and password in [mattermost] section of matterbridge.conf
|
||||
|
||||
## FAQ
|
||||
Please look at [matterbridge.conf.sample] (https://github.com/42wim/matterbridge/blob/master/matterbridge.conf.sample) for more information first.
|
||||
### Mattermost doesn't show the IRC nicks
|
||||
If you're running the webhooks version, this can be fixed by either:
|
||||
* enabling "override usernames". See [mattermost documentation](http://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks)
|
||||
* setting ```PrefixMessagesWithNick``` to ```true``` in ```mattermost``` section of your matterbridge.conf.
|
||||
|
||||
If you're running the plus version you'll need to:
|
||||
* setting ```PrefixMessagesWithNick``` to ```true``` in ```mattermost``` section of your matterbridge.conf.
|
||||
|
||||
Also look at the ```RemoteNickFormat``` setting.
|
25
README.md
25
README.md
@ -1,7 +1,7 @@
|
||||
# matterbridge
|
||||
Click on one of the badges below to join the chat
|
||||
|
||||
[](https://gitter.im/42wim/matterbridge) [](https://webchat.freenode.net/?channels=matterbridgechat) [](https://discord.gg/AkKPtrQ) [](https://riot.im/app/#/room/#matterbridge:matrix.org) [](https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA) [](https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e)
|
||||
[](https://gitter.im/42wim/matterbridge) [](https://webchat.freenode.net/?channels=matterbridgechat) [](https://discord.gg/AkKPtrQ) [](https://riot.im/app/#/room/#matterbridge:matrix.org) [](https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA) [](https://framateam.org/signup_user_complete/?id=tfqm33ggop8x3qgu4boeieta6e) 
|
||||
|
||||
[](https://github.com/42wim/matterbridge/releases/latest) [](https://bintray.com/42wim/nightly/Matterbridge/_latestVersion)
|
||||
|
||||
@ -49,7 +49,7 @@ Accounts to one of the supported bridges
|
||||
|
||||
# Installing
|
||||
## Binaries
|
||||
* Latest stable release [v0.16.2](https://github.com/42wim/matterbridge/releases/latest)
|
||||
* Latest stable release [v0.16.3](https://github.com/42wim/matterbridge/releases/latest)
|
||||
* Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)
|
||||
|
||||
## Building
|
||||
@ -84,12 +84,12 @@ See [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config
|
||||
|
||||
[mattermost]
|
||||
[mattermost.work]
|
||||
useAPI=true
|
||||
Server="yourmattermostserver.tld"
|
||||
Team="yourteam"
|
||||
Login="yourlogin"
|
||||
Password="yourpass"
|
||||
PrefixMessagesWithNick=true
|
||||
RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
|
||||
|
||||
[[gateway]]
|
||||
name="mygateway"
|
||||
@ -107,7 +107,6 @@ enable=true
|
||||
```
|
||||
[slack]
|
||||
[slack.test]
|
||||
useAPI=true
|
||||
Token="yourslacktoken"
|
||||
PrefixMessagesWithNick=true
|
||||
|
||||
@ -133,11 +132,8 @@ RemoteNickFormat="[{PROTOCOL}/{BRIDGE}] <{NICK}> "
|
||||
```
|
||||
|
||||
# Running
|
||||
1) Copy the matterbridge.toml.sample to matterbridge.toml
|
||||
2) Edit matterbridge.toml with the settings for your environment.
|
||||
3) Now you can run matterbridge. (```./matterbridge```)
|
||||
|
||||
(Matterbridge will only look for the config file in your current directory, if it isn't there specify -conf "/path/toyour/matterbridge.toml")
|
||||
See [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
|
||||
|
||||
```
|
||||
Usage of ./matterbridge:
|
||||
@ -162,18 +158,7 @@ See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.m
|
||||
|
||||
# FAQ
|
||||
|
||||
Please look at [matterbridge.toml.sample](https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.sample) for more information first.
|
||||
|
||||
## Mattermost doesn't show the IRC nicks
|
||||
If you're running the webhooks version, this can be fixed by either:
|
||||
* enabling "override usernames". See [mattermost documentation](http://docs.mattermost.com/developer/webhooks-incoming.html#enabling-incoming-webhooks)
|
||||
* setting ```PrefixMessagesWithNick``` to ```true``` in ```mattermost``` section of your matterbridge.toml.
|
||||
|
||||
If you're running the API version you'll need to:
|
||||
* setting ```PrefixMessagesWithNick``` to ```true``` in ```mattermost``` section of your matterbridge.toml.
|
||||
|
||||
Also look at the ```RemoteNickFormat``` setting.
|
||||
|
||||
See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ)
|
||||
|
||||
# Thanks
|
||||
Matterbridge wouldn't exist without these libraries:
|
||||
|
@ -222,6 +222,9 @@ func (b *Bslack) handleSlack() {
|
||||
if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" && message.Username == b.si.User.Name {
|
||||
continue
|
||||
}
|
||||
if message.Text == "" || message.Username == "" {
|
||||
continue
|
||||
}
|
||||
texts := strings.Split(message.Text, "\n")
|
||||
for _, text := range texts {
|
||||
text = b.replaceURL(text)
|
||||
@ -279,7 +282,8 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
|
||||
}
|
||||
m.Raw = ev
|
||||
m.Text = b.replaceMention(m.Text)
|
||||
if ev.BotID != "" {
|
||||
// when using webhookURL we can't check if it's our webhook or not for now
|
||||
if ev.BotID != "" && b.Config.WebhookURL == "" {
|
||||
bot, err := b.rtm.GetBotInfo(ev.BotID)
|
||||
if err != nil {
|
||||
continue
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"crypto/tls"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/jpillora/backoff"
|
||||
"github.com/mattn/go-xmpp"
|
||||
|
||||
"strings"
|
||||
@ -43,7 +44,29 @@ func (b *Bxmpp) Connect() error {
|
||||
return err
|
||||
}
|
||||
flog.Info("Connection succeeded")
|
||||
go b.handleXmpp()
|
||||
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
|
||||
}
|
||||
|
||||
@ -96,7 +119,11 @@ func (b *Bxmpp) xmppKeepAlive() chan bool {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
b.xc.PingC2S("", "")
|
||||
flog.Debugf("PING")
|
||||
err := b.xc.PingC2S("", "")
|
||||
if err != nil {
|
||||
flog.Debugf("PING failed %#v", err)
|
||||
}
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
|
@ -1,3 +1,10 @@
|
||||
# v0.16.3
|
||||
## Bugfix
|
||||
* general: Fix in/out logic. Closes #224
|
||||
* general: Fix message modification
|
||||
* slack: Disable message from other bots when using webhooks (slack)
|
||||
* mattermost: Return better error messages on mattermost connect
|
||||
|
||||
# v0.16.2
|
||||
## New features
|
||||
* general: binary builds against latest commit are now available on https://bintray.com/42wim/nightly/Matterbridge/_latestVersion
|
||||
|
@ -138,45 +138,48 @@ RECONNECT:
|
||||
br.JoinChannels()
|
||||
}
|
||||
|
||||
func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) {
|
||||
for _, br := range cfg {
|
||||
if isApi(br.Account) {
|
||||
br.Channel = "api"
|
||||
}
|
||||
ID := br.Channel + br.Account
|
||||
if _, ok := gw.Channels[ID]; !ok {
|
||||
channel := &config.ChannelInfo{Name: br.Channel, Direction: direction, ID: ID, Options: br.Options, Account: br.Account,
|
||||
GID: make(map[string]bool), SameChannel: make(map[string]bool)}
|
||||
channel.GID[gw.Name] = true
|
||||
channel.SameChannel[gw.Name] = br.SameChannel
|
||||
gw.Channels[channel.ID] = channel
|
||||
} else {
|
||||
// if we already have a key and it's not our current direction it means we have a bidirectional inout
|
||||
if gw.Channels[ID].Direction != direction {
|
||||
gw.Channels[ID].Direction = "inout"
|
||||
}
|
||||
}
|
||||
gw.Channels[ID].GID[gw.Name] = true
|
||||
gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
|
||||
}
|
||||
}
|
||||
func (gw *Gateway) mapChannels() error {
|
||||
for _, br := range append(gw.MyConfig.Out, gw.MyConfig.InOut...) {
|
||||
if isApi(br.Account) {
|
||||
br.Channel = "api"
|
||||
}
|
||||
ID := br.Channel + br.Account
|
||||
_, ok := gw.Channels[ID]
|
||||
if !ok {
|
||||
channel := &config.ChannelInfo{Name: br.Channel, Direction: "out", ID: ID, Options: br.Options, Account: br.Account,
|
||||
GID: make(map[string]bool), SameChannel: make(map[string]bool)}
|
||||
channel.GID[gw.Name] = true
|
||||
channel.SameChannel[gw.Name] = br.SameChannel
|
||||
gw.Channels[channel.ID] = channel
|
||||
}
|
||||
gw.Channels[ID].GID[gw.Name] = true
|
||||
gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
|
||||
}
|
||||
|
||||
for _, br := range append(gw.MyConfig.In, gw.MyConfig.InOut...) {
|
||||
if isApi(br.Account) {
|
||||
br.Channel = "api"
|
||||
}
|
||||
ID := br.Channel + br.Account
|
||||
_, ok := gw.Channels[ID]
|
||||
if !ok {
|
||||
channel := &config.ChannelInfo{Name: br.Channel, Direction: "in", ID: ID, Options: br.Options, Account: br.Account,
|
||||
GID: make(map[string]bool), SameChannel: make(map[string]bool)}
|
||||
channel.GID[gw.Name] = true
|
||||
channel.SameChannel[gw.Name] = br.SameChannel
|
||||
gw.Channels[channel.ID] = channel
|
||||
}
|
||||
gw.Channels[ID].GID[gw.Name] = true
|
||||
gw.Channels[ID].SameChannel[gw.Name] = br.SameChannel
|
||||
}
|
||||
gw.mapChannelConfig(gw.MyConfig.In, "in")
|
||||
gw.mapChannelConfig(gw.MyConfig.Out, "out")
|
||||
gw.mapChannelConfig(gw.MyConfig.InOut, "inout")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []config.ChannelInfo {
|
||||
var channels []config.ChannelInfo
|
||||
// if source channel is in only, do nothing
|
||||
for _, channel := range gw.Channels {
|
||||
// lookup the channel from the message
|
||||
if channel.ID == getChannelID(*msg) {
|
||||
// we only have destinations if the original message is from an "in" (sending) channel
|
||||
if !strings.Contains(channel.Direction, "in") {
|
||||
return channels
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, channel := range gw.Channels {
|
||||
if _, ok := gw.Channels[getChannelID(*msg)]; !ok {
|
||||
continue
|
||||
@ -191,8 +194,7 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if channel.Direction == "out" && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
|
||||
if strings.Contains(channel.Direction, "out") && channel.Account == dest.Account && gw.validGatewayDest(msg, channel) {
|
||||
channels = append(channels, *channel)
|
||||
}
|
||||
}
|
||||
@ -218,8 +220,8 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) {
|
||||
}
|
||||
log.Debugf("Sending %#v from %s (%s) to %s (%s)", msg, msg.Account, originchannel, dest.Account, channel.Name)
|
||||
msg.Channel = channel.Name
|
||||
gw.modifyAvatar(&msg, dest)
|
||||
gw.modifyUsername(&msg, dest)
|
||||
msg.Avatar = gw.modifyAvatar(origmsg, dest)
|
||||
msg.Username = gw.modifyUsername(origmsg, dest)
|
||||
// for api we need originchannel as channel
|
||||
if dest.Protocol == "api" {
|
||||
msg.Channel = originchannel
|
||||
@ -259,7 +261,7 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
|
||||
func (gw *Gateway) modifyUsername(msg config.Message, dest *bridge.Bridge) string {
|
||||
br := gw.Bridges[msg.Account]
|
||||
msg.Protocol = br.Protocol
|
||||
nick := gw.Config.General.RemoteNickFormat
|
||||
@ -281,10 +283,10 @@ func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
|
||||
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
|
||||
return nick
|
||||
}
|
||||
|
||||
func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) {
|
||||
func (gw *Gateway) modifyAvatar(msg config.Message, dest *bridge.Bridge) string {
|
||||
iconurl := gw.Config.General.IconURL
|
||||
if iconurl == "" {
|
||||
iconurl = dest.Config.IconURL
|
||||
@ -293,6 +295,7 @@ func (gw *Gateway) modifyAvatar(msg *config.Message, dest *bridge.Bridge) {
|
||||
if msg.Avatar == "" {
|
||||
msg.Avatar = iconurl
|
||||
}
|
||||
return msg.Avatar
|
||||
}
|
||||
|
||||
func (gw *Gateway) modifyMessage(msg *config.Message) {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
version = "0.16.2"
|
||||
version = "0.16.3"
|
||||
githash string
|
||||
)
|
||||
|
||||
|
@ -112,7 +112,10 @@ func (m *MMClient) Login() error {
|
||||
for {
|
||||
d := b.Duration()
|
||||
// bogus call to get the serverversion
|
||||
m.Client.GetClientProperties()
|
||||
_, err := m.Client.GetClientProperties()
|
||||
if err != nil {
|
||||
return fmt.Errorf("%#v", err.Error())
|
||||
}
|
||||
if firstConnection && !supportedVersion(m.Client.ServerVersion) {
|
||||
return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion)
|
||||
}
|
||||
|
50
migration.md
50
migration.md
@ -1,50 +0,0 @@
|
||||
# Breaking changes from 0.4 to 0.5 for matterbridge (webhooks version)
|
||||
## IRC section
|
||||
### Server
|
||||
Port removed, added to server
|
||||
```
|
||||
server="irc.freenode.net"
|
||||
port=6667
|
||||
```
|
||||
changed to
|
||||
```
|
||||
server="irc.freenode.net:6667"
|
||||
```
|
||||
### Channel
|
||||
Removed see Channels section below
|
||||
|
||||
### UseSlackCircumfix=true
|
||||
Removed, can be done by using ```RemoteNickFormat="<{NICK}> "```
|
||||
|
||||
## Mattermost section
|
||||
### BindAddress
|
||||
Port removed, added to BindAddress
|
||||
|
||||
```
|
||||
BindAddress="0.0.0.0"
|
||||
port=9999
|
||||
```
|
||||
|
||||
changed to
|
||||
|
||||
```
|
||||
BindAddress="0.0.0.0:9999"
|
||||
```
|
||||
|
||||
### Token
|
||||
Removed
|
||||
|
||||
## Channels section
|
||||
```
|
||||
[Token "outgoingwebhooktoken1"]
|
||||
IRCChannel="#off-topic"
|
||||
MMChannel="off-topic"
|
||||
```
|
||||
|
||||
changed to
|
||||
|
||||
```
|
||||
[Channel "channelnameofchoice"]
|
||||
IRC="#off-topic"
|
||||
Mattermost="off-topic"
|
||||
```
|
Reference in New Issue
Block a user