Thumbnail

rani/matterbridge.git

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

commit 11e00a54a54972de5d27db37fb494317a90495bf Author: Wim <wim@42.be> Date: Thu Sep 21 22:35:21 2017 +0000 Download files from slack and reupload to mattermost (slack/mattermost). Closes #255 Refactor message.Extra to a map[string][]interface{} to have a bit more flexibility for stuffing extra stuff. For attached files from slack, files < 1MB size get downloaded (in memory), and get put into Extra["file"][]config.FileInfo (containing a pointer to the buffer and the filename). This is not async so slack channels with lots of attached files may suffer a slowdown. (the download timeout is set at 5 seconds). diff --git a/bridge/config/config.go b/bridge/config/config.go index 2b678d2..c6686a4 100644 --- a/bridge/config/config.go +++ b/bridge/config/config.go @@ -297 +2912 @@ type Message struct {   Gateway string `json:"gateway"`   Timestamp time.Time `json:"timestamp"`   ID string `json:"id"` - Extra []interface{} + Extra map[string][]interface{} +} + +type FileInfo struct { + Name string + Data *[]byte  }    type ChannelInfo struct { diff --git a/bridge/mattermost/mattermost.go b/bridge/mattermost/mattermost.go index bedd07a..985d0d7 100644 --- a/bridge/mattermost/mattermost.go +++ b/bridge/mattermost/mattermost.go @@ -267 +267 @@ type MMMessage struct {   UserID string   ID string   Event string - Extra []interface{} + Extra map[string][]interface{}  }    type Bmattermost struct { @@ -1796 +17921 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) {   }   return msg.ID, b.mc.DeleteMessage(msg.ID)   } + if msg.Extra != nil { + for _, f := range msg.Extra["file"] { + fi := f.(config.FileInfo) + id, err := b.mc.UploadFile(*fi.Data, b.mc.GetChannelId(channel, ""), fi.Name) + if err != nil { + flog.Debugf("ERROR %#v", err) + return "", err + } + message = "uploaded a file: " + fi.Name + if b.Config.PrefixMessagesWithNick { + message = nick + "uploaded a file: " + fi.Name + } + return b.mc.PostMessageWithFiles(b.mc.GetChannelId(channel, ""), message, []string{id}) + } + }   if msg.ID != "" {   return b.mc.EditMessage(msg.ID, message)   } @@ -2257 +2407 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {   continue   }   - m := &MMMessage{} + m := &MMMessage{Extra: make(map[string][]interface{})}     props := message.Post.Props   if props != nil { @@ -2377 +2527 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {   message.Username = props["override_username"].(string)   }   if _, ok := props["attachments"].([]interface{}); ok { - m.Extra = props["attachments"].([]interface{}) + m.Extra["attachments"] = props["attachments"].([]interface{})   }   }   // do not post our own messages back to irc diff --git a/bridge/slack/slack.go b/bridge/slack/slack.go index 0469d7a..d72a222 100644 --- a/bridge/slack/slack.go +++ b/bridge/slack/slack.go @@ -16 +17 @@  package bslack    import ( + "bytes"   "errors"   "fmt"   "github.com/42wim/matterbridge/bridge/config" @@ -86 +98 @@ import (   log "github.com/Sirupsen/logrus"   "github.com/nlopes/slack"   "html" + "io" + "net/http"   "regexp"   "strings"   "time" @@ -2507 +2537 @@ func (b *Bslack) handleSlack() {   text = b.replaceURL(text)   text = html.UnescapeString(text)   flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) - msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID, ID: "slack " + message.Raw.Timestamp} + msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID, ID: "slack " + message.Raw.Timestamp, Extra: make(map[string][]interface{})}   if message.Raw.SubType == "me_message" {   msg.Event = config.EVENT_USER_ACTION   } @@ -2676 +27019 @@ func (b *Bslack) handleSlack() {   msg.Event = config.EVENT_MSG_DELETE   msg.ID = "slack " + message.Raw.DeletedTimestamp   } + + // if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra + if message.Raw.File != nil { + // limit to 1MB for now + if message.Raw.File.Size <= 1000000 { + data, err := b.downloadFile(message.Raw.File.URLPrivateDownload) + if err != nil { + flog.Errorf("download %s failed %#v", message.Raw.File.URLPrivateDownload, err) + } else { + msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: message.Raw.File.Name, Data: data}) + } + } + }   flog.Debugf("Message is %#v", msg)   b.Remote <- msg   } @@ -3989 +4149 @@ func (b *Bslack) replaceURL(text string) string {   return text  }   -func (b *Bslack) createAttach(extra []interface{}) []slack.Attachment { +func (b *Bslack) createAttach(extra map[string][]interface{}) []slack.Attachment {   var attachs []slack.Attachment - for _, v := range extra { + for _, v := range extra["attachments"] {   entry := v.(map[string]interface{})   s := slack.Attachment{}   s.Fallback = entry["fallback"].(string) @@ -4203 +43624 @@ func (b *Bslack) createAttach(extra []interface{}) []slack.Attachment {   }   return attachs  } + +func (b *Bslack) downloadFile(url string) (*[]byte, error) { + var buf bytes.Buffer + client := &http.Client{ + Timeout: time.Second * 5, + } + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + req.Header.Add("Authorization", "Bearer "+b.Config.Token) + resp, err := client.Do(req) + if err != nil { + resp.Body.Close() + return nil, err + } + io.Copy(&buf, resp.Body) + data := buf.Bytes() + resp.Body.Close() + return &data, nil +} diff --git a/gateway/gateway.go b/gateway/gateway.go index 7c1f3bd..663c387 100644 --- a/gateway/gateway.go +++ b/gateway/gateway.go @@ -2117 +2117 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool {   }   if msg.Text == "" {   // we have an attachment - if msg.Extra != nil { + if msg.Extra != nil && msg.Extra["attachments"] != nil {   return false   }   log.Debugf("ignoring empty message %#v from %s", msg, msg.Account)