diff options
Diffstat (limited to 'connector')
-rw-r--r-- | connector/mattermost/mattermost.go | 299 |
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, + }) + } + } + } +} |