diff options
author | Alex Auvolat <alex@adnab.me> | 2020-02-21 18:08:40 +0100 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2020-02-21 18:08:40 +0100 |
commit | fd768a10be36ec31f674fa291fcbe77b78a2855c (patch) | |
tree | bb9e736bfc9425e1ce5ee22379e8d46470af4d18 /connector | |
parent | ddd5936fb1f92432123a9a30d1d3a1fa644a4f8e (diff) | |
download | easybridge-fd768a10be36ec31f674fa291fcbe77b78a2855c.tar.gz easybridge-fd768a10be36ec31f674fa291fcbe77b78a2855c.zip |
Mattermost media objects in both ways + user/team profile pictures from MM to Matrix
Diffstat (limited to 'connector')
-rw-r--r-- | connector/connector.go | 2 | ||||
-rw-r--r-- | connector/irc/irc.go | 14 | ||||
-rw-r--r-- | connector/mattermost/mattermost.go | 146 | ||||
-rw-r--r-- | connector/mediaobject.go | 3 | ||||
-rw-r--r-- | connector/xmpp/xmpp.go | 13 |
5 files changed, 142 insertions, 36 deletions
diff --git a/connector/connector.go b/connector/connector.go index 2bf1704..2235318 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -115,7 +115,7 @@ type Event struct { Text string // Attached files such as images - Attachements []MediaObject + Attachments []MediaObject } type UserInfo struct { diff --git a/connector/irc/irc.go b/connector/irc/irc.go index 38aa79d..2ed3923 100644 --- a/connector/irc/irc.go +++ b/connector/irc/irc.go @@ -205,9 +205,17 @@ func (irc *IRC) Send(event *Event) error { return fmt.Errorf("Invalid target") } - if event.Attachements != nil && len(event.Attachements) > 0 { - // TODO find a way to send them using some hosing of some kind - return fmt.Errorf("Attachements not supported on IRC") + if event.Attachments != nil && len(event.Attachments) > 0 { + for _, at := range event.Attachments { + url := at.URL() + if url == "" { + // TODO find a way to send them using some hosing of some kind + return fmt.Errorf("Attachment without URL sent to IRC") + } else { + irc.conn.Cmd.Message(dest, fmt.Sprintf("%s (%s, %dkb)", + url, at.Mimetype(), at.Size()/1024)) + } + } } if event.Type == EVENT_MESSAGE { diff --git a/connector/mattermost/mattermost.go b/connector/mattermost/mattermost.go index 330026a..73ea66b 100644 --- a/connector/mattermost/mattermost.go +++ b/connector/mattermost/mattermost.go @@ -1,10 +1,12 @@ package mattermost import ( + "net/http" "fmt" _ "os" "strings" "time" + "io/ioutil" "encoding/json" "github.com/mattermost/mattermost-server/model" @@ -210,9 +212,6 @@ func (mm *Mattermost) Leave(roomId RoomID) { } func (mm *Mattermost) Send(event *Event) error { - // TODO: attachements - // TODO: verify private messages work - post := &model.Post{ Message: event.Text, } @@ -248,8 +247,30 @@ func (mm *Mattermost) Send(event *Event) error { return fmt.Errorf("Invalid target") } + if event.Attachments != nil { + post.FileIds = []string{} + for _, file := range event.Attachments { + rdr, err := file.Read() + if err != nil { + return err + } + defer rdr.Close() + data, err := ioutil.ReadAll(rdr) + if err != nil { + return err + } + up_file, err := mm.conn.UploadFile(data, post.ChannelId, file.Filename()) + if err != nil { + log.Warnf("UploadFile error: %s", err) + return err + } + post.FileIds = append(post.FileIds, up_file) + } + } + _, resp := mm.conn.Client.CreatePost(post) if resp.Error != nil { + log.Warnf("CreatePost error: %s", resp.Error) return resp.Error } return nil @@ -277,16 +298,58 @@ func (mm *Mattermost) handleConnected() { if len(strings.Split(ch.Name, "__")) == 2 { continue // This is a DM channel } + id := mm.reverseRoomId(ch.Id) - chName := ch.DisplayName - if teamName := mm.conn.GetTeamName(ch.TeamId); teamName != "" { - chName = teamName + " / " + chName - } mm.handler.Joined(id) - mm.handler.RoomInfoUpdated(id, UserID(""), &RoomInfo{ - Name: chName, + + // Update room info + room_info := &RoomInfo{ + Name: ch.DisplayName, Topic: ch.Header, - }) + } + for _, t := range mm.conn.OtherTeams { + if t.Id == ch.TeamId { + if t.Team.DisplayName != "" { + room_info.Name = t.Team.DisplayName + " / " + room_info.Name + } else { + room_info.Name = t.Team.Name + " / " + room_info.Name + } + // TODO: cache last update time so we don't do this needlessly + if t.Team.LastTeamIconUpdate > 0 { + team_img, resp := mm.conn.Client.GetTeamIcon(t.Id, "") + if resp.Error == nil { + room_info.Picture = &BlobMediaObject{ + ObjectFilename: t.Team.Name, + ObjectMimetype: http.DetectContentType(team_img), + ObjectData: team_img, + } + } else { + log.Warnf("Could not get team image: %s", resp.Error) + } + } + break + } + } + mm.handler.RoomInfoUpdated(id, UserID(""), room_info) + + // Update member list + members, resp := mm.conn.Client.GetChannelMembers(ch.Id, 0, 1000, "") + if resp.Error == nil { + for _, mem := range *members { + if mem.UserId == mm.conn.User.Id { + continue + } + user := mm.conn.GetUser(mem.UserId) + if user != nil { + mm.ensureJoined(user, id) + mm.updateUserInfo(user) + } else { + log.Warnf("Could not find joined user: %s", mem.UserId) + } + } + } else { + log.Warnf("Could not get channel members: %s", resp.Error) + } } } @@ -306,6 +369,45 @@ func (mm *Mattermost) handleLoop(msgCh chan *matterclient.Message, quitCh chan b } } +func (mm *Mattermost) updateUserInfo(user *model.User) { + userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server)) + userDisp := user.GetDisplayName(model.SHOW_NICKNAME_FULLNAME) + + if lastdn, ok := mm.userdisplaynamemap[userId]; !ok || lastdn != userDisp { + ui := &UserInfo{ + DisplayName: userDisp, + } + if user.LastPictureUpdate > 0 { + // TODO: cache last update time so we don't do this needlessly + img, resp := mm.conn.Client.GetProfileImage(user.Id, "") + if resp.Error == nil { + ui.Avatar = &BlobMediaObject{ + ObjectFilename: user.Username, + ObjectMimetype: http.DetectContentType(img), + ObjectData: img, + } + } else { + log.Warnf("Could not get profile picture: %s", resp.Error) + } + mm.handler.UserInfoUpdated(userId, ui) + mm.userdisplaynamemap[userId] = userDisp + } + } +} + +func (mm *Mattermost) ensureJoined(user *model.User, roomId RoomID) { + userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server)) + cache_key := fmt.Sprintf("%s / %s", userId, roomId) + if _, ok := mm.sentjoinedmap[cache_key]; !ok { + mm.handler.Event(&Event{ + Author: userId, + Room: roomId, + Type: EVENT_JOIN, + }) + mm.sentjoinedmap[cache_key] = true + } +} + func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { channel_name := msg.Data["channel_name"].(string) post_str := msg.Data["post"].(string) @@ -326,14 +428,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { return fmt.Errorf("Invalid user") } userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server)) - - userDisp := user.GetDisplayName(model.SHOW_NICKNAME_FULLNAME) - if lastdn, ok := mm.userdisplaynamemap[userId]; !ok || lastdn != userDisp { - mm.handler.UserInfoUpdated(userId, &UserInfo{ - DisplayName: userDisp, - }) - mm.userdisplaynamemap[userId] = userDisp - } + mm.updateUserInfo(user) // Build message event msg_ev := &Event{ @@ -347,7 +442,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { // Handle files if post.FileIds != nil && len(post.FileIds) > 0 { - msg_ev.Attachements = []MediaObject{} + msg_ev.Attachments = []MediaObject{} for _, file := range post.Metadata.Files { blob, resp := mm.conn.Client.GetFile(file.Id) if resp.Error != nil { @@ -355,7 +450,6 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { } media_object := &BlobMediaObject{ ObjectFilename: file.Name, - ObjectSize: file.Size, ObjectMimetype: file.MimeType, ObjectData: blob, } @@ -365,7 +459,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { Height: file.Height, } } - msg_ev.Attachements = append(msg_ev.Attachements, media_object) + msg_ev.Attachments = append(msg_ev.Attachments, media_object) } } @@ -384,15 +478,7 @@ func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error { return fmt.Errorf("Invalid channel id") } - cache_key := fmt.Sprintf("%s / %s", userId, roomId) - if _, ok := mm.sentjoinedmap[cache_key]; !ok { - mm.handler.Event(&Event{ - Author: userId, - Room: roomId, - Type: EVENT_JOIN, - }) - mm.sentjoinedmap[cache_key] = true - } + mm.ensureJoined(user, roomId) if post.Type == "system_header_change" { new_header := post.Props["new_header"].(string) diff --git a/connector/mediaobject.go b/connector/mediaobject.go index c6634b7..a8d6f9a 100644 --- a/connector/mediaobject.go +++ b/connector/mediaobject.go @@ -97,7 +97,6 @@ func (m *UrlMediaObject) URL() string { type BlobMediaObject struct { ObjectFilename string - ObjectSize int64 ObjectMimetype string ObjectImageSize *ImageSize ObjectData []byte @@ -108,7 +107,7 @@ func (m *BlobMediaObject) Filename() string { } func (m *BlobMediaObject) Size() int64 { - return m.ObjectSize + return int64(len(m.ObjectData)) } func (m *BlobMediaObject) Mimetype() string { diff --git a/connector/xmpp/xmpp.go b/connector/xmpp/xmpp.go index b18e670..02d1a96 100644 --- a/connector/xmpp/xmpp.go +++ b/connector/xmpp/xmpp.go @@ -308,6 +308,19 @@ func (xm *XMPP) Leave(roomId RoomID) { } func (xm *XMPP) Send(event *Event) error { + if event.Attachments != nil && len(event.Attachments) > 0 { + for _, at := range event.Attachments { + url := at.URL() + if url == "" { + // TODO find a way to send them using some hosing of some kind + return fmt.Errorf("Attachment without URL sent to XMPP") + } else { + event.Text += fmt.Sprintf("\n%s (%s, %dkb)", + url, at.Mimetype(), at.Size()/1024) + } + } + } + fmt.Printf("xm *XMPP Send %#v\n", event) if len(event.Recipient) > 0 { _, err := xm.conn.Send(gxmpp.Chat{ |