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: 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, }) } } } }