Add REST API support

This commit is contained in:
Wim 2017-02-18 23:10:22 +01:00
parent 930b639cc9
commit 73f01ad8d8
7 changed files with 146 additions and 7 deletions

View File

@ -1,13 +1,14 @@
# matterbridge
![matterbridge.gif](https://s15.postimg.org/qpjhp6y3f/matterbridge.gif)
Simple bridge between mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat and Hipchat(via xmpp).
Simple bridge between mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat and Hipchat(via xmpp) with REST API.
* Relays public channel messages between multiple mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat and Hipchat (via xmpp). Pick and mix.
* Supports multiple channels.
* Matterbridge can also work with private groups on your mattermost.
* Allow for bridging the same bridges, which means you can eg bridge between multiple mattermosts.
* The bridge is now a gateway which has support multiple in and out bridges. (and supports multiple gateways).
* REST API to read/post messages to bridges (WIP)
Look at [matterbridge.toml.sample] (https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.sample) for documentation and an example.
Look at [matterbridge.toml.simple] (https://github.com/42wim/matterbridge/blob/master/matterbridge.toml.simple) for a simple example.

91
bridge/api/api.go Normal file
View File

@ -0,0 +1,91 @@
package api
import (
"github.com/42wim/matterbridge/bridge/config"
log "github.com/Sirupsen/logrus"
"github.com/labstack/echo"
"github.com/zfjagann/golang-ring"
"net/http"
"sync"
)
type Api struct {
Config *config.Protocol
Remote chan config.Message
Account string
Messages ring.Ring
sync.RWMutex
}
type ApiMessage struct {
Text string `json:"text"`
Username string `json:"username"`
Avatar string `json:"avatar"`
}
var flog *log.Entry
var protocol = "api"
func init() {
flog = log.WithFields(log.Fields{"module": protocol})
}
func New(cfg config.Protocol, account string, c chan config.Message) *Api {
b := &Api{}
e := echo.New()
b.Messages = ring.Ring{}
b.Messages.SetCapacity(cfg.Buffer)
b.Config = &cfg
b.Account = account
b.Remote = c
e.GET("/api/messages", b.handleMessages)
e.POST("/api/message", b.handlePostMessage)
go func() {
flog.Fatal(e.Start(cfg.BindAddress))
}()
return b
}
func (b *Api) Connect() error {
return nil
}
func (b *Api) Disconnect() error {
return nil
}
func (b *Api) JoinChannel(channel string) error {
return nil
}
func (b *Api) Send(msg config.Message) error {
b.Lock()
defer b.Unlock()
b.Messages.Enqueue(&msg)
return nil
}
func (b *Api) handlePostMessage(c echo.Context) error {
message := &ApiMessage{}
if err := c.Bind(message); err != nil {
return err
}
b.Remote <- config.Message{
Text: message.Text,
Username: message.Username,
Channel: "api",
Avatar: message.Avatar,
Account: b.Account,
}
return c.JSON(http.StatusOK, message)
}
func (b *Api) handleMessages(c echo.Context) error {
b.Lock()
defer b.Unlock()
for _, msg := range b.Messages.Values() {
c.JSONPretty(http.StatusOK, msg, " ")
}
b.Messages = ring.Ring{}
return nil
}

View File

@ -1,6 +1,7 @@
package bridge
import (
"github.com/42wim/matterbridge/bridge/api"
"github.com/42wim/matterbridge/bridge/config"
"github.com/42wim/matterbridge/bridge/discord"
"github.com/42wim/matterbridge/bridge/gitter"
@ -70,6 +71,9 @@ func New(cfg *config.Config, bridge *config.Bridge, c chan config.Message) *Brid
case "rocketchat":
b.Config = cfg.Rocketchat[name]
b.Bridger = brocketchat.New(cfg.Rocketchat[name], bridge.Account, c)
case "api":
b.Config = cfg.Api[name]
b.Bridger = api.New(cfg.Api[name], bridge.Account, c)
}
return b
}

View File

@ -6,6 +6,7 @@ import (
"os"
"reflect"
"strings"
"time"
)
const (
@ -14,16 +15,19 @@ const (
)
type Message struct {
Text string
Channel string
Username string
Avatar string
Account string
Event string
Text string
Channel string
Username string
Avatar string
Account string
Event string
Protocol string
Timestamp time.Time
}
type Protocol struct {
BindAddress string // mattermost, slack
Buffer int // api
IconURL string // mattermost, slack
IgnoreNicks string // all protocols
Jid string // xmpp
@ -79,6 +83,7 @@ type SameChannelGateway struct {
}
type Config struct {
Api map[string]Protocol
IRC map[string]Protocol
Mattermost map[string]Protocol
Slack map[string]Protocol

View File

@ -1,4 +1,7 @@
# v0.9.3-dev
## New features
* API: rest interface to read / post messages (see API section in matterbridge.toml.sample)
## Bugfix
* slack: fix receiving messages from private channels #118
* slack: fix echo when using webhooks #119

View File

@ -86,6 +86,7 @@ func (gw *Gateway) handleReceive() {
}
}
if !gw.ignoreMessage(&msg) {
msg.Timestamp = time.Now()
for _, br := range gw.Bridges {
gw.handleMessage(msg, br)
}
@ -165,6 +166,10 @@ 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)
gw.modifyUsername(&msg, dest)
// for api we need originchannel as channel
if dest.Protocol == "api" {
msg.Channel = originchannel
}
err := dest.Send(msg)
if err != nil {
fmt.Println(err)
@ -199,6 +204,7 @@ func (gw *Gateway) modifyMessage(msg *config.Message, dest *bridge.Bridge) {
func (gw *Gateway) modifyUsername(msg *config.Message, dest *bridge.Bridge) {
br := gw.Bridges[msg.Account]
msg.Protocol = br.Protocol
nick := gw.Config.General.RemoteNickFormat
if nick == "" {
nick = dest.Config.RemoteNickFormat

View File

@ -486,6 +486,28 @@ RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
#OPTIONAL (default false)
ShowJoinPart=false
###################################################################
#API
###################################################################
[api]
#You can configure multiple API hooks
#In this example we use [api.local]
#REQUIRED
[api.local]
#Address to listen on for API
#REQUIRED
BindAddress="127.0.0.1:4242"
#Amount of messages to keep in memory
Buffer=1000
#RemoteNickFormat defines how remote users appear on this bridge
#The string "{NICK}" (case sensitive) will be replaced by the actual nick / username.
#The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge
#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
#OPTIONAL (default empty)
RemoteNickFormat="{NICK}"
###################################################################
#General configuration
@ -572,6 +594,13 @@ enable=true
#OPTIONAL - your irc channel key
key="yourkey"
#API example
#[[gateway.inout]]
#account="api.local"
#channel="api"
#To send data to the api:
#curl -XPOST -H 'Content-Type: application/json' -d '{"text":"test","username":"randomuser"}' http://localhost:4242/api/message
#If you want to do a 1:1 mapping between protocols where the channelnames are the same
#e.g. slack and mattermost you can use the samechannelgateway configuration
#the example configuration below send messages from channel testing on mattermost to