summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--bridge/config/config.go2
-rw-r--r--bridge/zulip/zulip.go170
-rw-r--r--gateway/gateway.go2
-rw-r--r--matterbridge.toml.sample85
5 files changed, 262 insertions, 1 deletions
diff --git a/README.md b/README.md
index db451dab..42189ed8 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Click on one of the badges below to join the chat
![matterbridge.gif](https://github.com/42wim/matterbridge/blob/master/img/matterbridge.gif)
-Simple bridge between IRC, XMPP, Gitter, Mattermost, Slack, Discord, Telegram, Rocket.Chat, Hipchat(via xmpp), Matrix, Steam and ssh-chat
+Simple bridge between IRC, XMPP, Gitter, Mattermost, Slack, Discord, Telegram, Rocket.Chat, Hipchat(via xmpp), Matrix, Steam, ssh-chat and Zulip
Has a REST API.
Minecraft server chat support via [MatterLink](https://github.com/elytra/MatterLink)
@@ -62,6 +62,7 @@ Accounts to one of the supported bridges
* [Steam](https://store.steampowered.com/)
* [Twitch](https://twitch.tv)
* [Ssh-chat](https://github.com/shazow/ssh-chat)
+* [Zulip](https://zulipchat.com)
# Screenshots
See https://github.com/42wim/matterbridge/wiki
@@ -189,6 +190,7 @@ Matterbridge wouldn't exist without these libraries:
* echo - https://github.com/labstack/echo
* gitter - https://github.com/sromku/go-gitter
* gops - https://github.com/google/gops
+* gozulipbot - https://github.com/ifo/gozulipbot
* irc - https://github.com/lrstanley/girc
* mattermost - https://github.com/mattermost/platform
* matrix - https://github.com/matrix-org/gomatrix
diff --git a/bridge/config/config.go b/bridge/config/config.go
index 1b92f83c..0fc41412 100644
--- a/bridge/config/config.go
+++ b/bridge/config/config.go
@@ -107,6 +107,7 @@ type Protocol struct {
StripNick bool // all protocols
Team string // mattermost
Token string // gitter, slack, discord, api
+ Topic string // zulip
URL string // mattermost, slack // DEPRECATED
UseAPI bool // mattermost, slack
UseSASL bool // IRC
@@ -159,6 +160,7 @@ type ConfigValues struct {
Telegram map[string]Protocol
Rocketchat map[string]Protocol
Sshchat map[string]Protocol
+ Zulip map[string]Protocol
General Protocol
Gateway []Gateway
SameChannelGateway []SameChannelGateway
diff --git a/bridge/zulip/zulip.go b/bridge/zulip/zulip.go
new file mode 100644
index 00000000..ebeabc1c
--- /dev/null
+++ b/bridge/zulip/zulip.go
@@ -0,0 +1,170 @@
+package bzulip
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "strconv"
+ "time"
+
+ "github.com/42wim/matterbridge/bridge"
+ "github.com/42wim/matterbridge/bridge/config"
+ "github.com/42wim/matterbridge/bridge/helper"
+ gzb "github.com/matterbridge/gozulipbot"
+)
+
+type Bzulip struct {
+ q *gzb.Queue
+ bot *gzb.Bot
+ streams map[int]string
+ *bridge.Config
+}
+
+func New(cfg *bridge.Config) bridge.Bridger {
+ return &Bzulip{Config: cfg, streams: make(map[int]string)}
+}
+
+func (b *Bzulip) Connect() error {
+ bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login")}
+ bot.Init()
+ q, err := bot.RegisterAll()
+ b.q = q
+ b.bot = &bot
+ if err != nil {
+ b.Log.Errorf("Connect() %#v", err)
+ return err
+ }
+ // init stream
+ b.getChannel(0)
+ b.Log.Info("Connection succeeded")
+ go b.handleQueue()
+ return nil
+}
+
+func (b *Bzulip) Disconnect() error {
+ return nil
+}
+
+func (b *Bzulip) JoinChannel(channel config.ChannelInfo) error {
+ return nil
+}
+
+func (b *Bzulip) Send(msg config.Message) (string, error) {
+ b.Log.Debugf("=> Receiving %#v", msg)
+
+ // Delete message
+ if msg.Event == config.EVENT_MSG_DELETE {
+ if msg.ID == "" {
+ return "", nil
+ }
+ _, err := b.bot.UpdateMessage(msg.ID, "")
+ return "", err
+ }
+
+ // Upload a file if it exists
+ if msg.Extra != nil {
+ for _, rmsg := range helper.HandleExtra(&msg, b.General) {
+ b.sendMessage(rmsg)
+ }
+ if len(msg.Extra["file"]) > 0 {
+ return b.handleUploadFile(&msg)
+ }
+ }
+
+ // edit the message if we have a msg ID
+ if msg.ID != "" {
+ _, err := b.bot.UpdateMessage(msg.ID, msg.Username+msg.Text)
+ return "", err
+ }
+
+ // Post normal message
+ return b.sendMessage(msg)
+}
+
+func (b *Bzulip) getChannel(id int) string {
+ if name, ok := b.streams[id]; ok {
+ return name
+ }
+ streams, err := b.bot.GetRawStreams()
+ if err != nil {
+ b.Log.Errorf("getChannel: %#v", err)
+ return ""
+ }
+ for _, stream := range streams.Streams {
+ b.streams[stream.StreamID] = stream.Name
+ }
+ if name, ok := b.streams[id]; ok {
+ return name
+ }
+ return ""
+}
+
+func (b *Bzulip) handleQueue() error {
+ for {
+ messages, _ := b.q.GetEvents()
+ for _, m := range messages {
+ b.Log.Debugf("== Receiving %#v", m)
+ // ignore our own messages
+ if m.SenderEmail == b.GetString("login") {
+ continue
+ }
+ rmsg := config.Message{Username: m.SenderFullName, Text: m.Content, Channel: b.getChannel(m.StreamID), Account: b.Account, UserID: strconv.Itoa(m.SenderID), Avatar: m.AvatarURL}
+ b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
+ b.Log.Debugf("<= Message is %#v", rmsg)
+ b.Remote <- rmsg
+ b.q.LastEventID = m.ID
+ }
+ time.Sleep(time.Second * 3)
+ }
+}
+
+func (b *Bzulip) sendMessage(msg config.Message) (string, error) {
+ topic := "matterbridge"
+ if b.GetString("topic") != "" {
+ topic = b.GetString("topic")
+ }
+ m := gzb.Message{
+ Stream: msg.Channel,
+ Topic: topic,
+ Content: msg.Username + msg.Text,
+ }
+ resp, err := b.bot.Message(m)
+ if err != nil {
+ return "", err
+ }
+ if resp != nil {
+ defer resp.Body.Close()
+ res, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return "", err
+ }
+ var jr struct {
+ ID int `json:"id"`
+ }
+ err = json.Unmarshal(res, &jr)
+ if err != nil {
+ return "", err
+ }
+ return strconv.Itoa(jr.ID), nil
+ }
+ return "", nil
+}
+
+func (b *Bzulip) handleUploadFile(msg *config.Message) (string, error) {
+ for _, f := range msg.Extra["file"] {
+ fi := f.(config.FileInfo)
+ if fi.Comment != "" {
+ msg.Text += fi.Comment + ": "
+ }
+ if fi.URL != "" {
+ msg.Text = fi.URL
+ if fi.Comment != "" {
+ msg.Text = fi.Comment + ": " + fi.URL
+ }
+ }
+ _, err := b.sendMessage(*msg)
+ if err != nil {
+ return "", err
+ }
+ }
+ return "", nil
+}
diff --git a/gateway/gateway.go b/gateway/gateway.go
index 0dddf897..eb5bbe92 100644
--- a/gateway/gateway.go
+++ b/gateway/gateway.go
@@ -17,6 +17,7 @@ import (
"github.com/42wim/matterbridge/bridge/steam"
"github.com/42wim/matterbridge/bridge/telegram"
"github.com/42wim/matterbridge/bridge/xmpp"
+ "github.com/42wim/matterbridge/bridge/zulip"
log "github.com/sirupsen/logrus"
// "github.com/davecgh/go-spew/spew"
"crypto/sha1"
@@ -62,6 +63,7 @@ var bridgeMap = map[string]bridge.Factory{
"steam": bsteam.New,
"telegram": btelegram.New,
"xmpp": bxmpp.New,
+ "zulip": bzulip.New,
}
func init() {
diff --git a/matterbridge.toml.sample b/matterbridge.toml.sample
index f814f1a7..d28dc8bd 100644
--- a/matterbridge.toml.sample
+++ b/matterbridge.toml.sample
@@ -1156,6 +1156,90 @@ StripNick=false
ShowTopicChange=false
###################################################################
+#zulip section
+###################################################################
+[zulip]
+#You can configure multiple servers "[zulip.name]" or "[zulip.name2]"
+#In this example we use [zulip.streamchat]
+#REQUIRED
+
+[zulip.streamchat]
+#Token to connect with zulip API (called bot API key in Settings - Your bots)
+#REQUIRED
+Token="Yourtokenhere"
+
+#Username of the bot, normally called yourbot-bot@yourserver.zulipchat.com
+#See username in Settings - Your bots
+#REQUIRED
+Login="yourbot-bot@yourserver.zulipchat.com"
+
+#Servername of your zulip instance
+#REQUIRED
+Server="https://yourserver.zulipchat.com"
+
+#Topic of the messages matterbridge will use
+#OPTIONAL (default "matterbridge")
+Topic="matterbridge"
+
+## RELOADABLE SETTINGS
+## Settings below can be reloaded by editing the file
+
+#Nicks you want to ignore.
+#Messages from those users will not be sent to other bridges.
+#OPTIONAL
+IgnoreNicks="spammer1 spammer2"
+
+#Messages you want to ignore.
+#Messages matching these regexp will be ignored and not sent to other bridges
+#See https://regex-golang.appspot.com/assets/html/index.html for more regex info
+#OPTIONAL (example below ignores messages starting with ~~ or messages containing badword
+IgnoreMessages="^~~ badword"
+
+#messages you want to replace.
+#it replaces outgoing messages from the bridge.
+#so you need to place it by the sending bridge definition.
+#regular expressions supported
+#some examples:
+#this replaces cat => dog and sleep => awake
+#replacemessages=[ ["cat","dog"], ["sleep","awake"] ]
+#this replaces every number with number. 123 => numbernumbernumber
+#replacemessages=[ ["[0-9]","number"] ]
+#optional (default empty)
+ReplaceMessages=[ ["cat","dog"] ]
+
+#nicks you want to replace.
+#see replacemessages for syntaxa
+#optional (default empty)
+ReplaceNicks=[ ["user--","user"] ]
+
+#extra label that can be used in the RemoteNickFormat
+#optional (default empty)
+Label=""
+
+#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 "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge
+#The string "{PROTOCOL}" (case sensitive) will be replaced by the protocol used by the bridge
+#OPTIONAL (default empty)
+RemoteNickFormat="[{PROTOCOL}] <{NICK}> "
+
+#Enable to show users joins/parts from other bridges
+#Currently works for messages from the following bridges: irc, mattermost, slack
+#OPTIONAL (default false)
+ShowJoinPart=false
+
+#StripNick only allows alphanumerical nicks. See https://github.com/42wim/matterbridge/issues/285
+#It will strip other characters from the nick
+#OPTIONAL (default false)
+StripNick=false
+
+#Enable to show topic changes from other bridges
+#Only works hiding/show topic changes from slack bridge for now
+#OPTIONAL (default false)
+ShowTopicChange=false
+
+###################################################################
#API
###################################################################
[api]
@@ -1283,6 +1367,7 @@ enable=true
# - encrypted rooms are not supported in matrix
#steam - chatid (a large number).
# The number in the URL when you click "enter chat room" in the browser
+ #zulip - stream (without the #)
#
#REQUIRED
channel="#testing"