Thumbnail

rani/matterbridge.git

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

commit a80aa7d1946a6e2cc4ca617798b48183127be871 Author: Wim <wim@42.be> Date: Mon May 07 21:35:48 2018 +0000 Add initial zulip support diff --git a/README.md b/README.md index db451da..42189ed 100644 --- a/README.md +++ b/README.md @@ -77 +77 @@ 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)   @@ -626 +627 @@ 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 @@ -1896 +1907 @@ 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 1b92f83..0fc4141 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -1076 +1077 @@ 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 @@ -1596 +1607 @@ 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 0000000..ebeabc1 --- /dev/null +++ b/bridge/zulip/zulip.go @@ -00 +1170 @@ +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 0dddf89..eb5bbe9 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -176 +177 @@ 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" @@ -626 +637 @@ 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 f814f1a..d28dc8b 100644 --- a/matterbridge.toml.sample +++ b/matterbridge.toml.sample @@ -11556 +115590 @@ StripNick=false  #OPTIONAL (default 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  ################################################################### @@ -12836 +13677 @@ 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"