4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-06-26 13:09:24 +00:00

Compare commits

...

12 Commits

Author SHA1 Message Date
Wim
e99532fb89 Release v0.16.1 2017-07-15 16:59:57 +02:00
Wim
4aa646f6b0 Use GetFileLinks. Also show links to non-public files (mattermost) 2017-07-15 16:51:10 +02:00
Wim
9dcd51fb80 Refactor connecting logic slack/mattermost. Fixes #216 2017-07-15 16:49:47 +02:00
Wim
6dee988b76 Fix megacheck / go vet issues 2017-07-14 00:35:01 +02:00
Wim
5af40db396 Update travis 2017-07-14 00:28:46 +02:00
Wim
b3553bee7a Add travis 2017-07-13 23:54:07 +02:00
Wim
ac19c94b9f Add GetFileLinks, also get files if public links is disabled 2017-07-12 22:47:30 +02:00
Wim
845f7dc331 Update readme 2017-07-10 22:21:11 +02:00
Wim
2adeae37e1 Update readme 2017-07-10 22:19:51 +02:00
Wim
16eb12b2a0 Bump version 2017-07-10 21:59:17 +02:00
Wim
8411f2aa32 Lookup bot username (slack). #213 2017-07-10 21:58:43 +02:00
Wim
e8acc49cbd Add slack badge / invitation 2017-07-09 18:08:30 +02:00
16 changed files with 227 additions and 102 deletions

34
.travis.yml Normal file
View File

@ -0,0 +1,34 @@
language: go
go:
- 1.7.x
- 1.8.x
- tip
install: true
matrix:
# It's ok if our code fails on unstable development versions of Go.
allow_failures:
- go: tip
# Don't wait for tip tests to finish. Mark the test run green if the
# tests pass on the stable versions of Go.
fast_finish: true
notifications:
email: false
before_script:
- GO_FILES=$(find . -iname '*.go' | grep -v /vendor/) # All the .go files, excluding vendor/
- PKGS=$(go list ./... | grep -v /vendor/) # All the import paths, excluding vendor/
# - go get github.com/golang/lint/golint # Linter
- go get honnef.co/go/tools/cmd/megacheck # Badass static analyzer/linter
# Anything in before_script: that returns a nonzero exit code will
# flunk the build and immediately stop. It's sorta like having
# set -e enabled in bash.
script:
script:
- test -z $(gofmt -s -l $GO_FILES) # Fail if a .go file hasn't been formatted with gofmt
#- go test -v -race $PKGS # Run all the tests with the race detector enabled
- go vet $PKGS # go vet is the official Go static analyzer
- megacheck $PKGS # "go vet on steroids" + linter
#- golint -set_exit_status $PKGS # one last linter

View File

@ -1,5 +1,7 @@
# matterbridge
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/42wim/matterbridge) [![Join the IRC chat at https://webchat.freenode.net/?channels=matterbridgechat](https://img.shields.io/badge/IRC-matterbridgechat-green.svg)](https://webchat.freenode.net/?channels=matterbridgechat) [![Discord](https://img.shields.io/badge/discord-matterbridge-green.svg)](https://discord.gg/AkKPtrQ) [![Matrix](https://img.shields.io/badge/matrix-matterbridge-green.svg)](https://riot.im/app/#/room/#matterbridge:matrix.org)
Click on one of the badges below to join the chat
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/42wim/matterbridge) [![Join the IRC chat at https://webchat.freenode.net/?channels=matterbridgechat](https://img.shields.io/badge/IRC-matterbridgechat-green.svg)](https://webchat.freenode.net/?channels=matterbridgechat) [![Discord](https://img.shields.io/badge/discord-matterbridge-green.svg)](https://discord.gg/AkKPtrQ) [![Matrix](https://img.shields.io/badge/matrix-matterbridge-green.svg)](https://riot.im/app/#/room/#matterbridge:matrix.org) [![Slack](https://img.shields.io/badge/slack-matterbridgechat-green.svg)](https://join.slack.com/matterbridgechat/shared_invite/MjEwODMxNjU1NDMwLTE0OTk2MTU3NTMtMzZkZmRiNDZhOA)
![matterbridge.gif](https://s15.postimg.org/qpjhp6y3f/matterbridge.gif)
@ -13,6 +15,7 @@ Has a REST API.
* [Binaries](#binaries)
* [Building](#building)
* [Configuration](#configuration)
* [Howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config)
* [Examples](#examples)
* [Running](#running)
* [Docker](#docker)
@ -45,7 +48,7 @@ Accounts to one of the supported bridges
# Installing
## Binaries
Binaries can be found [here] (https://github.com/42wim/matterbridge/releases/)
* Latest stable release [v0.16.0](https://github.com/42wim/matterbridge/releases/tag/v0.16.0)
* Latest stable release [v0.16.1](https://github.com/42wim/matterbridge/releases/tag/v0.16.1)
## 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)
@ -63,12 +66,12 @@ matterbridge
```
# Configuration
* [matterbridge.toml.sample](https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.sample) for documentation and an example.
* [matterbridge.toml.simple](https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.simple) for a simple example.
## Create a configuration.
## Basic configuration
See [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration.
## Advanced configuration
* [matterbridge.toml.sample](https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.sample) for documentation and an example.
## Examples
### Bridge mattermost (off-topic) - irc (#testing)
```

View File

@ -88,10 +88,7 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid
func (b *Bridge) JoinChannels() error {
err := b.joinChannels(b.Channels, b.Joined)
if err != nil {
return err
}
return nil
return err
}
func (b *Bridge) joinChannels(channels map[string]config.ChannelInfo, exists map[string]bool) error {

View File

@ -209,7 +209,7 @@ func Deprecated(cfg Protocol, account string) bool {
log.Printf("ERROR: %s BindAddress is deprecated, you need to change it to WebhookBindAddress.", account)
} else if cfg.URL != "" {
log.Printf("ERROR: %s URL is deprecated, you need to change it to WebhookURL.", account)
} else if cfg.UseAPI == true {
} else if cfg.UseAPI {
log.Printf("ERROR: %s UseAPI is deprecated, it's enabled by default, please remove it from your config file.", account)
} else {
return false

View File

@ -4,6 +4,7 @@ import (
"strings"
)
/*
func tableformatter(nicks []string, nicksPerRow int, continued bool) string {
result := "|IRC users"
if continued {
@ -29,6 +30,7 @@ func tableformatter(nicks []string, nicksPerRow int, continued bool) string {
}
return result
}
*/
func plainformatter(nicks []string, nicksPerRow int) string {
return strings.Join(nicks, ", ") + " currently on IRC"

View File

@ -148,9 +148,9 @@ func (b *Birc) Send(msg config.Message) error {
func (b *Birc) doSend() {
rate := time.Millisecond * time.Duration(b.Config.MessageDelay)
throttle := time.Tick(rate)
throttle := time.NewTicker(rate)
for msg := range b.Local {
<-throttle
<-throttle.C
b.i.Privmsg(msg.Channel, msg.Username+msg.Text)
}
}

View File

@ -1,6 +1,7 @@
package bmattermost
import (
"errors"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/matterclient"
"github.com/42wim/matterbridge/matterhook"
@ -12,9 +13,8 @@ type MMhook struct {
}
type MMapi struct {
mc *matterclient.MMClient
mmMap map[string]string
mmIgnoreNicks []string
mc *matterclient.MMClient
mmMap map[string]string
}
type MMMessage struct {
@ -29,7 +29,6 @@ type Bmattermost struct {
MMapi
Config *config.Protocol
Remote chan config.Message
name string
TeamId string
Account string
}
@ -55,33 +54,49 @@ func (b *Bmattermost) Command(cmd string) string {
}
func (b *Bmattermost) Connect() error {
if b.Config.WebhookURL != "" && b.Config.WebhookBindAddress != "" {
flog.Info("Connecting using webhookurl and webhookbindaddress")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
BindAddress: b.Config.WebhookBindAddress})
} else if b.Config.WebhookURL != "" {
flog.Info("Connecting using webhookurl (for posting) and token")
if b.Config.WebhookBindAddress != "" {
if b.Config.WebhookURL != "" {
flog.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)")
} else if b.Config.Login != "" {
flog.Info("Connecting using login/password (sending)")
err := b.apiLogin()
if err != nil {
return err
}
} else {
flog.Info("Connecting using webhookbindaddress (receiving)")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
BindAddress: b.Config.WebhookBindAddress})
}
go b.handleMatter()
return nil
}
if b.Config.WebhookURL != "" {
flog.Info("Connecting using webhookurl (sending)")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
DisableServer: true})
} else {
flog.Info("Connecting using token")
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.Infof("Connecting %s (team: %s) on %s", b.Config.Login, b.Config.Team, b.Config.Server)
err := b.mc.Login()
if b.Config.Login != "" {
flog.Info("Connecting using login/password (receiving)")
err := b.apiLogin()
if err != nil {
return err
}
go b.handleMatter()
}
return nil
} else if b.Config.Login != "" {
flog.Info("Connecting using login/password (sending and receiving)")
err := b.apiLogin()
if err != nil {
return err
}
flog.Info("Connection succeeded")
b.TeamId = b.mc.GetTeamId()
go b.mc.WsReceiver()
go b.mc.StatusLoop()
go b.handleMatter()
}
if b.Config.WebhookBindAddress == "" && b.Config.WebhookURL == "" && b.Config.Login == "" {
return errors.New("No connection method found. See that you have WebhookBindAddress, WebhookURL or Login/Password/Server/Team configured.")
}
go b.handleMatter()
return nil
}
@ -126,11 +141,11 @@ func (b *Bmattermost) Send(msg config.Message) error {
func (b *Bmattermost) handleMatter() {
mchan := make(chan *MMMessage)
if b.Config.WebhookBindAddress != "" && b.Config.WebhookURL != "" {
if b.Config.WebhookBindAddress != "" {
flog.Debugf("Choosing webhooks based receiving")
go b.handleMatterHook(mchan)
} else {
flog.Debugf("Choosing login (api) based receiving")
flog.Debugf("Choosing login/password based receiving")
go b.handleMatterClient(mchan)
}
for message := range mchan {
@ -166,7 +181,7 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
m.Text = message.Text + b.Config.EditSuffix
}
if len(message.Post.FileIds) > 0 {
for _, link := range b.mc.GetPublicLinks(message.Post.FileIds) {
for _, link := range b.mc.GetFileLinks(message.Post.FileIds) {
m.Text = m.Text + "\n" + link
}
}
@ -187,3 +202,20 @@ func (b *Bmattermost) handleMatterHook(mchan chan *MMMessage) {
mchan <- m
}
}
func (b *Bmattermost) apiLogin() error {
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.Infof("Connecting %s (team: %s) on %s", b.Config.Login, b.Config.Team, b.Config.Server)
err := b.mc.Login()
if err != nil {
return err
}
flog.Info("Connection succeeded")
b.TeamId = b.mc.GetTeamId()
go b.mc.WsReceiver()
go b.mc.StatusLoop()
return nil
}

View File

@ -16,7 +16,6 @@ type Brocketchat struct {
MMhook
Config *config.Protocol
Remote chan config.Message
name string
Account string
}

View File

@ -1,6 +1,7 @@
package bslack
import (
"errors"
"fmt"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/matterhook"
@ -53,22 +54,52 @@ func (b *Bslack) Command(cmd string) string {
}
func (b *Bslack) Connect() error {
if b.Config.WebhookURL != "" && b.Config.WebhookBindAddress != "" {
flog.Info("Connecting using webhookurl and webhookbindaddress")
if b.Config.WebhookBindAddress != "" {
if b.Config.WebhookURL != "" {
flog.Info("Connecting using webhookurl (sending) and webhookbindaddress (receiving)")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
BindAddress: b.Config.WebhookBindAddress})
} else if b.Config.Token != "" {
flog.Info("Connecting using token (sending)")
b.sc = slack.New(b.Config.Token)
b.rtm = b.sc.NewRTM()
go b.rtm.ManageConnection()
flog.Info("Connecting using webhookbindaddress (receiving)")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
BindAddress: b.Config.WebhookBindAddress})
} else {
flog.Info("Connecting using webhookbindaddress (receiving)")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
BindAddress: b.Config.WebhookBindAddress})
}
go b.handleSlack()
return nil
}
if b.Config.WebhookURL != "" {
flog.Info("Connecting using webhookurl (sending)")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{BindAddress: b.Config.WebhookBindAddress})
} else if b.Config.WebhookURL != "" {
flog.Info("Connecting using webhookurl (for posting) and token")
b.mh = matterhook.New(b.Config.WebhookURL,
matterhook.Config{DisableServer: true})
} else {
flog.Info("Connecting using token")
matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify,
DisableServer: true})
if b.Config.Token != "" {
flog.Info("Connecting using token (receiving)")
b.sc = slack.New(b.Config.Token)
b.rtm = b.sc.NewRTM()
go b.rtm.ManageConnection()
go b.handleSlack()
}
} else if b.Config.Token != "" {
flog.Info("Connecting using token (sending and receiving)")
b.sc = slack.New(b.Config.Token)
b.rtm = b.sc.NewRTM()
go b.rtm.ManageConnection()
go b.handleSlack()
}
if b.Config.WebhookBindAddress == "" && b.Config.WebhookURL == "" && b.Config.Token == "" {
return errors.New("No connection method found. See that you have WebhookBindAddress, WebhookURL or Token configured.")
}
flog.Info("Connection succeeded")
go b.handleSlack()
return nil
}
@ -79,7 +110,7 @@ func (b *Bslack) Disconnect() error {
func (b *Bslack) JoinChannel(channel string) error {
// we can only join channels using the API
if b.Config.WebhookURL == "" || b.Config.WebhookBindAddress == "" {
if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" {
if strings.HasPrefix(b.Config.Token, "xoxb") {
// TODO check if bot has already joined channel
return nil
@ -120,7 +151,7 @@ func (b *Bslack) Send(msg config.Message) error {
return err
}
np := slack.NewPostMessageParameters()
if b.Config.PrefixMessagesWithNick == true {
if b.Config.PrefixMessagesWithNick {
np.AsUser = true
}
np.Username = nick
@ -176,7 +207,7 @@ func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) {
func (b *Bslack) handleSlack() {
mchan := make(chan *MMMessage)
if b.Config.WebhookBindAddress != "" && b.Config.WebhookURL != "" {
if b.Config.WebhookBindAddress != "" {
flog.Debugf("Choosing webhooks based receiving")
go b.handleMatterHook(mchan)
} else {
@ -229,6 +260,15 @@ func (b *Bslack) handleSlackClient(mchan chan *MMMessage) {
m.Text = ev.Text
m.Raw = ev
m.Text = b.replaceMention(m.Text)
if ev.BotID != "" && user.Name == "" {
bot, err := b.rtm.GetBotInfo(ev.BotID)
if err != nil {
continue
}
if bot.Name != "" {
m.Username = bot.Name
}
}
mchan <- m
}
count++

View File

@ -136,7 +136,7 @@ func (b *Bsteam) handleEvents() {
myLoginInfo.AuthCode = code
}
default:
log.Errorf("LogOnFailedEvent: ", e.Result)
log.Errorf("LogOnFailedEvent: %#v ", e.Result)
// TODO: Handle EResult_InvalidLoginAuthCode
return
}

View File

@ -1,3 +1,11 @@
# v0.16.1
## New features
* slack: also relay messages of other bots #213
* mattermost: show also links if public links have not been enabled.
## Bugfix
* mattermost, slack: fix connecting logic #216
# v0.16.0
## Breaking Changes
* URL,UseAPI,BindAddress is deprecated. Your config has to be updated.

View File

@ -96,31 +96,28 @@ func (gw *Gateway) Start() error {
}
func (gw *Gateway) handleReceive() {
for {
select {
case msg := <-gw.Message:
if msg.Event == config.EVENT_FAILURE {
for _, br := range gw.Bridges {
if msg.Account == br.Account {
go gw.reconnectBridge(br)
}
for msg := range gw.Message {
if msg.Event == config.EVENT_FAILURE {
for _, br := range gw.Bridges {
if msg.Account == br.Account {
go gw.reconnectBridge(br)
}
}
if msg.Event == config.EVENT_REJOIN_CHANNELS {
for _, br := range gw.Bridges {
if msg.Account == br.Account {
br.Joined = make(map[string]bool)
br.JoinChannels()
}
}
if msg.Event == config.EVENT_REJOIN_CHANNELS {
for _, br := range gw.Bridges {
if msg.Account == br.Account {
br.Joined = make(map[string]bool)
br.JoinChannels()
}
continue
}
if !gw.ignoreMessage(&msg) {
msg.Timestamp = time.Now()
gw.modifyMessage(&msg)
for _, br := range gw.Bridges {
gw.handleMessage(msg, br)
}
continue
}
if !gw.ignoreMessage(&msg) {
msg.Timestamp = time.Now()
gw.modifyMessage(&msg)
for _, br := range gw.Bridges {
gw.handleMessage(msg, br)
}
}
}
@ -317,8 +314,8 @@ func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.Channel
// check if we are running a samechannelgateway.
// if it is and the channel name matches it's ok, otherwise we shouldn't use this channel.
for k, _ := range GIDmap {
if channel.SameChannel[k] == true {
for k := range GIDmap {
if channel.SameChannel[k] {
if msg.Channel == channel.Name {
// add the gateway to our message
msg.Gateway = k
@ -329,8 +326,8 @@ func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.Channel
}
}
// check if we are in the correct gateway
for k, _ := range GIDmap {
if channel.GID[k] == true {
for k := range GIDmap {
if channel.GID[k] {
// add the gateway to our message
msg.Gateway = k
return true
@ -340,8 +337,5 @@ func (gw *Gateway) validGatewayDest(msg *config.Message, channel *config.Channel
}
func isApi(account string) bool {
if strings.HasPrefix(account, "api.") {
return true
}
return false
return strings.HasPrefix(account, "api.")
}

View File

@ -99,10 +99,9 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Receive returns an incoming message from mattermost outgoing webhooks URL.
func (c *Client) Receive() Message {
for {
select {
case msg := <-c.In:
return msg
}
var msg Message
for msg = range c.In {
return msg
}
return msg
}

View File

@ -12,7 +12,7 @@ import (
)
var (
version = "0.16.0"
version = "0.16.1"
githash string
)

View File

@ -88,7 +88,7 @@ func (m *MMClient) SetLogLevel(level string) {
func (m *MMClient) Login() error {
// check if this is a first connect or a reconnection
firstConnection := true
if m.WsConnected == true {
if m.WsConnected {
firstConnection = false
}
m.WsConnected = false
@ -149,7 +149,7 @@ func (m *MMClient) Login() error {
return errors.New("invalid " + model.SESSION_COOKIE_TOKEN)
}
} else {
myinfo, appErr = m.Client.Login(m.Credentials.Login, m.Credentials.Pass)
_, appErr = m.Client.Login(m.Credentials.Login, m.Credentials.Pass)
}
if appErr != nil {
d := b.Duration()
@ -329,7 +329,6 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
}
rmsg.Text = data.Message
rmsg.Post = data
return
}
func (m *MMClient) UpdateUsers() error {
@ -500,6 +499,25 @@ func (m *MMClient) GetPublicLinks(filenames []string) []string {
return output
}
func (m *MMClient) GetFileLinks(filenames []string) []string {
uriScheme := "https://"
if m.NoTLS {
uriScheme = "http://"
}
var output []string
for _, f := range filenames {
res, err := m.Client.GetPublicLink(f)
if err != nil {
// public links is probably disabled, create the link ourselves
output = append(output, uriScheme+m.Credentials.Server+model.API_URL_SUFFIX_V3+"/files/"+f+"/get")
continue
}
output = append(output, res)
}
return output
}
func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
data := make(map[string]string)
data["channel_id"] = channelId
@ -516,7 +534,7 @@ func (m *MMClient) UpdateLastViewed(channelId string) {
if m.mmVersion() >= 3.08 {
view := model.ChannelView{ChannelId: channelId}
res, _ := m.Client.ViewChannel(view)
if res == false {
if !res {
m.log.Errorf("ChannelView update for %s failed", channelId)
}
return
@ -664,13 +682,13 @@ func (m *MMClient) GetUsers() map[string]*model.User {
func (m *MMClient) GetUser(userId string) *model.User {
m.Lock()
defer m.Unlock()
u, ok := m.Users[userId]
_, ok := m.Users[userId]
if !ok {
res, err := m.Client.GetProfilesByIds([]string{userId})
if err != nil {
return nil
}
u = res.Data.(map[string]*model.User)[userId]
u := res.Data.(map[string]*model.User)[userId]
m.Users[userId] = u
}
return m.Users[userId]

View File

@ -134,12 +134,11 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Receive returns an incoming message from mattermost outgoing webhooks URL.
func (c *Client) Receive() IMessage {
for {
select {
case msg := <-c.In:
return msg
}
var msg IMessage
for msg := range c.In {
return msg
}
return msg
}
// Send sends a msg to mattermost incoming webhooks URL.