aboutsummaryrefslogtreecommitdiff
path: root/connector
diff options
context:
space:
mode:
Diffstat (limited to 'connector')
-rw-r--r--connector/mattermost/mattermost.go299
1 files changed, 299 insertions, 0 deletions
diff --git a/connector/mattermost/mattermost.go b/connector/mattermost/mattermost.go
new file mode 100644
index 0000000..3520c2b
--- /dev/null
+++ b/connector/mattermost/mattermost.go
@@ -0,0 +1,299 @@
+package mattermost
+
+import (
+ "fmt"
+ _ "os"
+ "strings"
+ "time"
+
+ "github.com/mattermost/mattermost-server/model"
+ "github.com/42wim/matterbridge/matterclient"
+
+ . "git.deuxfleurs.fr/Deuxfleurs/easybridge/connector"
+)
+
+// User id format: nickname@server
+// Room id format: room_name@team@server
+
+type Mattermost struct {
+ handler Handler
+
+ server string
+ username string
+ team string
+
+ conn *matterclient.MMClient
+ handlerStopChan chan bool
+}
+
+
+func (mm *Mattermost) SetHandler(h Handler) {
+ mm.handler = h
+}
+
+func (mm *Mattermost) Protocol() string {
+ return "mattermost"
+}
+
+func (mm *Mattermost) Configure(c Configuration) error {
+ if mm.conn != nil {
+ mm.Close()
+ }
+
+ var err error
+
+ mm.server, err = c.GetString("server")
+ if err != nil {
+ return err
+ }
+
+ mm.username, err = c.GetString("username")
+ if err != nil {
+ return err
+ }
+
+ mm.team, err = c.GetString("team")
+ 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)
+ err = mm.conn.Login()
+ if err != nil {
+ return err
+ }
+ go mm.conn.WsReceiver()
+ go mm.conn.StatusLoop()
+
+ fmt.Printf("CLIENT4: %#v\n", mm.conn.Client)
+
+ for i := 0; i < 42; i++ {
+ time.Sleep(time.Duration(1) * time.Second)
+ if mm.conn.WsConnected {
+ mm.handleConnected()
+ return nil
+ }
+ }
+ return fmt.Errorf("Failed to connect after 42s attempting")
+}
+
+func (mm *Mattermost) User() UserID {
+ return UserID(mm.username + "@" + mm.server)
+}
+
+func (mm *Mattermost) getTeamIdByName(name string) string {
+ for _, team := range mm.conn.OtherTeams {
+ if team.Team.Name == name {
+ return team.Id
+ }
+ }
+ return ""
+}
+
+func (mm *Mattermost) checkRoomId(id RoomID) (string, error) {
+ x := strings.Split(string(id), "@")
+ if len(x) == 1 {
+ return "", fmt.Errorf("Please write whole room ID with team and server: %s@%s@%s", id, mm.team, mm.server)
+ }
+ if len(x) == 2 {
+ return x[0], nil
+ }
+ if len(x) != 3 || x[2] != mm.server {
+ return "", fmt.Errorf("Invalid room ID: %s", id)
+ }
+
+ team_id := mm.getTeamIdByName(x[1])
+ if team_id == "" {
+ return "", fmt.Errorf("Team not found: %s", id)
+ }
+
+ ch_id := mm.conn.GetChannelId(x[0], team_id)
+ if ch_id == "" {
+ return "", fmt.Errorf("Channel not found: %s", id)
+ }
+ return ch_id, nil
+}
+
+func (mm *Mattermost) reverseRoomId(id string) RoomID {
+ team := mm.conn.GetChannelTeamId(id)
+ if team == "" {
+ return RoomID(fmt.Sprintf("%s@%s", id, mm.server))
+ } else {
+ teamName := mm.conn.GetTeamName(team)
+ name := mm.conn.GetChannelName(id)
+ fmt.Printf("CHANNEL NAME: %s TEAM: %s\n", name, teamName)
+ return RoomID(fmt.Sprintf("%s@%s@%s", name, teamName, mm.server))
+ }
+}
+
+func (mm *Mattermost) checkUserId(id UserID) (string, error) {
+ x := strings.Split(string(id), "@")
+ if len(x) == 1 {
+ return "", fmt.Errorf("Please write whole user ID with server: %s@%s", id, mm.server)
+ }
+ if len(x) != 2 || x[1] != mm.server {
+ return "", fmt.Errorf("Invalid user ID: %s", id)
+ }
+ return x[0], nil
+}
+
+func (mm *Mattermost) SetUserInfo(info *UserInfo) error {
+ return fmt.Errorf("Not implemented")
+}
+
+func (mm *Mattermost) SetRoomInfo(roomId RoomID, info *RoomInfo) error {
+ ch, err := mm.checkRoomId(roomId)
+ if err != nil {
+ return err
+ }
+
+ if info.Topic != "" {
+ mm.conn.UpdateChannelHeader(ch, info.Topic)
+ }
+
+ if info.Picture != nil {
+ err = fmt.Errorf("Not supported: channel picture on mattermost")
+ }
+
+ if info.Name != "" {
+ err = fmt.Errorf("Not supported: channel name on mattermost")
+ }
+
+ return err
+}
+
+func (mm *Mattermost) Join(roomId RoomID) error {
+ ch, err := mm.checkRoomId(roomId)
+ if err != nil {
+ return err
+ }
+
+ return mm.conn.JoinChannel(ch)
+}
+
+func (mm *Mattermost) Invite(userId UserID, roomId RoomID) error {
+ return fmt.Errorf("Not supported: invite on mattermost")
+}
+
+func (mm *Mattermost) Leave(roomId RoomID) {
+ // Not supported? TODO
+}
+
+func (mm *Mattermost) Send(event *Event) error {
+ // TODO: actions
+ // TODO: attachements
+
+ if event.Room != "" {
+ ch, err := mm.checkRoomId(event.Room)
+ if err != nil {
+ return err
+ }
+ _, err = mm.conn.PostMessage(ch, event.Text, "")
+ return err
+ } else if event.Recipient != "" {
+ ui, err := mm.checkUserId(event.Recipient)
+ if err != nil {
+ return err
+ }
+ mm.conn.SendDirectMessage(ui, event.Text, "")
+ return nil
+ } else {
+ return fmt.Errorf("Invalid target")
+ }
+}
+
+func (mm *Mattermost) Close() {
+ mm.conn.WsQuit = true
+ if mm.handlerStopChan != nil {
+ mm.handlerStopChan <- true
+ mm.handlerStopChan = nil
+ }
+}
+
+func (mm *Mattermost) handleConnected() {
+ mm.handlerStopChan = make(chan bool)
+ go mm.handleLoop(mm.conn.MessageChan, mm.handlerStopChan)
+
+ fmt.Printf("Connected to mattermost\n")
+
+ chans := mm.conn.GetChannels()
+ for _, ch := range chans {
+ 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,
+ Topic: ch.Header,
+ })
+ }
+}
+
+func (mm *Mattermost) handleLoop(msgCh chan *matterclient.Message, quitCh chan bool) {
+ for {
+ select {
+ case <-quitCh:
+ break
+ case msg := <-msgCh:
+ 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 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,
+ })
+ }
+ }
+ }
+}