From 45296100df60f50f40fecbc9a8280ead2156269b Mon Sep 17 00:00:00 2001 From: Wim Date: Mon, 7 May 2018 21:35:48 +0200 Subject: Add initial zulip support --- bridge/config/config.go | 2 + bridge/zulip/zulip.go | 170 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 bridge/zulip/zulip.go (limited to 'bridge') 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 +} -- cgit v1.2.3