Thumbnail

rani/matterbridge.git

Clone URL: https://git.buni.party/rani/matterbridge.git

commit 8c5f6d7a798da7ada0c0675f20399204f3877472 Author: Wim <wim@42.be> Date: Sat Feb 18 23:10:22 2017 +0000 Add REST API support diff --git a/README.md b/README.md index dd7b1cb..add3c63 100644 --- a/README.md +++ b/README.md @@ -113 +114 @@  # 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. diff --git a/bridge/api/api.go b/bridge/api/api.go new file mode 100644 index 0000000..4870ee6 --- /dev/null +++ b/bridge/api/api.go @@ -00 +191 @@ +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 +} diff --git a/bridge/bridge.go b/bridge/bridge.go index db26c42..012b0ef 100644 --- a/bridge/bridge.go +++ b/bridge/bridge.go @@ -16 +17 @@  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" @@ -706 +719 @@ 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  } diff --git a/bridge/config/config.go b/bridge/config/config.go index 811c97a..4f6568a 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -66 +67 @@ import (   "os"   "reflect"   "strings" + "time"  )    const ( @@ -1416 +1519 @@ 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 @@ -796 +837 @@ type SameChannelGateway struct {  }    type Config struct { + Api map[string]Protocol   IRC map[string]Protocol   Mattermost map[string]Protocol   Slack map[string]Protocol diff --git a/changelog.md b/changelog.md index b45a35d..78015f9 100644 --- a/changelog.md +++ b/changelog.md @@ -14 +17 @@  # 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 diff --git a/gateway/gateway.go b/gateway/gateway.go index f965f8a..5e85926 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -866 +867 @@ func (gw *Gateway) handleReceive() {   }   }   if !gw.ignoreMessage(&msg) { + msg.Timestamp = time.Now()   for _, br := range gw.Bridges {   gw.handleMessage(msg, br)   } @@ -1656 +16610 @@ 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) @@ -1996 +2047 @@ 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 diff --git a/matterbridge.toml.sample b/matterbridge.toml.sample index e251d0e..0fa95d0 100644 --- a/matterbridge.toml.sample +++ b/matterbridge.toml.sample @@ -4866 +48628 @@ 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 @@ -5726 +59413 @@ 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