aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2020-02-18 17:17:04 +0100
committerAlex Auvolat <alex@adnab.me>2020-02-18 17:17:04 +0100
commitcf13f2b5af290c69bc4f1a8184b1dbe19225b36e (patch)
treea65be7436640761276c43d9db90f4a10b2ceccbc
parent78c7d1deae23d7807c130028883cf350348dc4db (diff)
downloadeasybridge-cf13f2b5af290c69bc4f1a8184b1dbe19225b36e.tar.gz
easybridge-cf13f2b5af290c69bc4f1a8184b1dbe19225b36e.zip
Handle mattermost private messages
-rw-r--r--appservice/names.go14
-rw-r--r--connector/mattermost/mattermost.go190
2 files changed, 130 insertions, 74 deletions
diff --git a/appservice/names.go b/appservice/names.go
index 4a5d186..9ed00f8 100644
--- a/appservice/names.go
+++ b/appservice/names.go
@@ -8,14 +8,16 @@ import (
)
func roomAlias(protocol string, id RoomID) string {
- id2 := strings.ReplaceAll(string(id), "#", "")
- id2 = strings.ReplaceAll(id2, "@", "__")
-
- return fmt.Sprintf("_ezbr__%s__%s", id2, protocol)
+ return fmt.Sprintf("_ezbr__%s__%s", safeStringForId(string(id)), protocol)
}
func userMxId(protocol string, id UserID) string {
- id2 := strings.ReplaceAll(string(id), "@", "__")
+ return fmt.Sprintf("_ezbr__%s__%s", safeStringForId(string(id)), protocol)
+}
- return fmt.Sprintf("_ezbr__%s__%s", id2, protocol)
+func safeStringForId(in string) string {
+ id2 := strings.ReplaceAll(in, "#", "")
+ id2 = strings.ReplaceAll(id2, "@", "__")
+ id2 = strings.ReplaceAll(id2, ":", "_")
+ return id2
}
diff --git a/connector/mattermost/mattermost.go b/connector/mattermost/mattermost.go
index 2dbc436..ca49c99 100644
--- a/connector/mattermost/mattermost.go
+++ b/connector/mattermost/mattermost.go
@@ -5,9 +5,11 @@ import (
_ "os"
"strings"
"time"
+ "encoding/json"
"github.com/mattermost/mattermost-server/model"
"github.com/42wim/matterbridge/matterclient"
+ log "github.com/sirupsen/logrus"
. "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
)
@@ -24,6 +26,8 @@ type Mattermost struct {
conn *matterclient.MMClient
handlerStopChan chan bool
+
+ usermap map[string]string // map username to user id
}
@@ -57,12 +61,18 @@ func (mm *Mattermost) Configure(c Configuration) error {
return err
}
+ notls, err := c.GetBool("no_tls", false)
+ if err != nil {
+ return err
+ }
+
password, _ := c.GetString("password", "")
token, _ := c.GetString("token", "")
if token != "" {
password = "token=" + token
}
mm.conn = matterclient.New(mm.username, password, mm.team, mm.server)
+ mm.conn.Credentials.NoTLS = notls
err = mm.conn.Login()
if err != nil {
return err
@@ -139,7 +149,15 @@ func (mm *Mattermost) checkUserId(id UserID) (string, error) {
if len(x) != 2 || x[1] != mm.server {
return "", fmt.Errorf("Invalid user ID: %s", id)
}
- return x[0], nil
+ if user_id, ok := mm.usermap[x[0]]; ok {
+ return user_id, nil
+ }
+ u, resp := mm.conn.Client.GetUserByUsername(x[0], "")
+ if u == nil || resp.Error != nil {
+ return "", fmt.Errorf("Not found: %s (%s)", x[0], resp.Error)
+ }
+ mm.usermap[x[0]] = u.Id
+ return u.Id, nil
}
func (mm *Mattermost) SetUserInfo(info *UserInfo) error {
@@ -177,6 +195,11 @@ func (mm *Mattermost) Join(roomId RoomID) error {
}
func (mm *Mattermost) Invite(userId UserID, roomId RoomID) error {
+ if roomId == "" {
+ _, err := mm.checkUserId(userId)
+ return err
+ }
+
return fmt.Errorf("Not supported: invite on mattermost")
}
@@ -185,26 +208,46 @@ func (mm *Mattermost) Leave(roomId RoomID) {
}
func (mm *Mattermost) Send(event *Event) error {
- // TODO: actions
// TODO: attachements
+ // TODO: verify private messages work
+
+ post := &model.Post{
+ Message: event.Text,
+ }
+ if event.Type == EVENT_ACTION {
+ post.Type = "me"
+ }
if event.Room != "" {
ch, err := mm.checkRoomId(event.Room)
if err != nil {
return err
}
- _, err = mm.conn.PostMessage(ch, event.Text, "")
- return err
+ post.ChannelId = ch
} else if event.Recipient != "" {
ui, err := mm.checkUserId(event.Recipient)
if err != nil {
return err
}
- mm.conn.SendDirectMessage(ui, event.Text, "")
- return nil
+
+ _, resp := mm.conn.Client.CreateDirectChannel(mm.conn.User.Id, ui)
+ if resp.Error != nil {
+ return resp.Error
+ }
+ channelName := model.GetDMNameFromIds(ui, mm.conn.User.Id)
+
+ err = mm.conn.UpdateChannels()
+ if err != nil {
+ return err
+ }
+
+ post.ChannelId = mm.conn.GetChannelId(channelName, "")
} else {
return fmt.Errorf("Invalid target")
}
+
+ _, resp := mm.conn.Client.CreatePost(post)
+ return resp.Error
}
func (mm *Mattermost) Close() {
@@ -217,6 +260,7 @@ func (mm *Mattermost) Close() {
func (mm *Mattermost) handleConnected() {
mm.handlerStopChan = make(chan bool)
+ mm.usermap = make(map[string]string)
go mm.handleLoop(mm.conn.MessageChan, mm.handlerStopChan)
fmt.Printf("Connected to mattermost\n")
@@ -246,69 +290,79 @@ func (mm *Mattermost) handleLoop(msgCh chan *matterclient.Message, quitCh chan b
break
case msg := <-msgCh:
fmt.Printf("Mattermost: %#v\n", msg)
- if len(strings.Split(msg.Channel, "__")) == 2 {
- // Private message
- ids := strings.Split(msg.Channel, "__")
- my_id := mm.conn.User.Id
- var them *model.User
- if ids[0] == my_id {
- them = mm.conn.GetUser(ids[1])
- } else {
- them = mm.conn.GetUser(ids[0])
- }
-
- if them != nil {
- user := UserID(fmt.Sprintf("%s@%s", them.Username, mm.server))
- mm.handler.Event(&Event{
- Author: user,
- Text: msg.Text,
- Type: EVENT_MESSAGE,
- })
- }
- } else {
- var room RoomID
- if msg.Team == "" {
- room = RoomID(fmt.Sprintf("%s@%s", msg.Channel, mm.server))
- } else {
- room = RoomID(fmt.Sprintf("%s@%s@%s", msg.Channel, msg.Team, mm.server))
- }
- _, err := mm.checkRoomId(room)
- if err != nil {
- fmt.Printf("Could not find channel: %s %s\n", msg.Channel, msg.Team)
- continue
- }
-
- user := UserID(fmt.Sprintf("%s@%s", msg.Username, mm.server))
-
- if strings.Contains(msg.Text, "updated the channel header") {
- splits := strings.SplitN(msg.Text, "to: ", 2)
- if len(splits) == 2 {
- if user == mm.User() {
- user = UserID("")
- }
- mm.handler.RoomInfoUpdated(room, user, &RoomInfo{
- Topic: splits[1],
- })
- continue
- }
- }
-
- if user == mm.User() {
- continue
- }
- // TODO don't join everytime
- mm.handler.Event(&Event{
- Author: user,
- Room: room,
- Type: EVENT_JOIN,
- })
- mm.handler.Event(&Event{
- Author: user,
- Room: room,
- Text: msg.Text,
- Type: EVENT_MESSAGE,
- })
+ fmt.Printf("Mattermost raw: %#v\n", msg.Raw)
+ err := mm.handlePosted(msg.Raw)
+ if err != nil {
+ log.Warnf("Mattermost error: %s", err)
}
}
}
}
+
+func (mm *Mattermost) handlePosted(msg *model.WebSocketEvent) error {
+ channel_name := msg.Data["channel_name"].(string)
+ post_str := msg.Data["post"].(string)
+ var post model.Post
+ err := json.Unmarshal([]byte(post_str), &post)
+ if err != nil {
+ return err
+ }
+
+ // Skip self messages
+ if post.UserId == mm.conn.User.Id {
+ return nil
+ }
+
+ // Find sending user
+ user := mm.conn.GetUser(post.UserId)
+ if user == nil {
+ return fmt.Errorf("Invalid user")
+ }
+ userId := UserID(fmt.Sprintf("%s@%s", user.Username, mm.server))
+
+ // Build message event
+ msg_ev := &Event{
+ Author: userId,
+ Text: post.Message,
+ Type: EVENT_MESSAGE,
+ }
+ if post.Type == "me" {
+ msg_ev.Type = EVENT_ACTION
+ }
+
+ // Dispatch as PM or as room message
+ if len(strings.Split(channel_name, "__")) == 2 {
+ // Private message, no need to find room id
+ if user.Id == mm.conn.User.Id {
+ // Skip self sent messages
+ return nil
+ }
+
+ mm.handler.Event(msg_ev)
+ } else {
+ roomId := mm.reverseRoomId(post.ChannelId)
+ if roomId == "" {
+ return fmt.Errorf("Invalid channel id")
+ }
+
+ // TODO don't join everytime
+ mm.handler.Event(&Event{
+ Author: userId,
+ Room: roomId,
+ Type: EVENT_JOIN,
+ })
+
+ if post.Type == "system_header_change" {
+ new_header := post.Props["new_header"].(string)
+ mm.handler.RoomInfoUpdated(roomId, userId, &RoomInfo{
+ Topic: new_header,
+ })
+ } else if post.Type == "" || post.Type == "me" {
+ msg_ev.Room = roomId
+ mm.handler.Event(msg_ev)
+ } else {
+ return fmt.Errorf("Unhandled post type: %s", post.Type)
+ }
+ }
+ return nil
+}