Skip to content

Commit

Permalink
Add ChannelMembers support to the slack bridge
Browse files Browse the repository at this point in the history
  • Loading branch information
42wim committed Jan 6, 2019
1 parent e28d2f5 commit b936afd
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 0 deletions.
52 changes: 52 additions & 0 deletions bridge/slack/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,58 @@ func (b *Bslack) handleDownloadFile(rmsg *config.Message, file *slack.File, retr
return nil
}

// handleGetChannelMembers handles messages containing the GetChannelMembers event
// Sends a message to the router containing *config.ChannelMembers
func (b *Bslack) handleGetChannelMembers(rmsg *config.Message) bool {
if rmsg.Event != config.EventGetChannelMembers {
return false
}

cMembers := config.ChannelMembers{}

b.channelMembersMutex.RLock()

for channelID, members := range b.channelMembers {
for _, member := range members {
channelName := ""
userName := ""
userNick := ""
user := b.getUser(member)
if user != nil {
userName = user.Name
userNick = user.Profile.DisplayName
}
channel, _ := b.getChannelByID(channelID)
if channel != nil {
channelName = channel.Name
}
cMember := config.ChannelMember{
Username: userName,
Nick: userNick,
UserID: member,
ChannelID: channelID,
ChannelName: channelName,
}
cMembers = append(cMembers, cMember)
}
}

b.channelMembersMutex.RUnlock()

extra := make(map[string][]interface{})
extra[config.EventGetChannelMembers] = append(extra[config.EventGetChannelMembers], cMembers)
msg := config.Message{
Extra: extra,
Event: config.EventGetChannelMembers,
Account: b.Account,
}

b.Log.Debugf("sending msg to remote %#v", msg)
b.Remote <- msg

return true
}

// fileCached implements Matterbridge's caching logic for files
// shared via Slack.
//
Expand Down
46 changes: 46 additions & 0 deletions bridge/slack/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ func (b *Bslack) populateUsers(wait bool) {
return
}
for b.refreshInProgress {
b.refreshMutex.Unlock()
time.Sleep(time.Second)
b.refreshMutex.Lock()
}
b.refreshInProgress = true
b.refreshMutex.Unlock()
Expand Down Expand Up @@ -139,13 +141,16 @@ func (b *Bslack) populateChannels(wait bool) {
return
}
for b.refreshInProgress {
b.refreshMutex.Unlock()
time.Sleep(time.Second)
b.refreshMutex.Lock()
}
b.refreshInProgress = true
b.refreshMutex.Unlock()

newChannelsByID := map[string]*slack.Channel{}
newChannelsByName := map[string]*slack.Channel{}
newChannelMembers := make(map[string][]string)

// We only retrieve public and private channels, not IMs
// and MPIMs as those do not have a channel name.
Expand All @@ -166,7 +171,18 @@ func (b *Bslack) populateChannels(wait bool) {
for i := range channels {
newChannelsByID[channels[i].ID] = &channels[i]
newChannelsByName[channels[i].Name] = &channels[i]
// also find all the members in every channel
members, err := b.getUsersInConversation(channels[i].ID)
if err != nil {
if err = b.handleRateLimit(err); err != nil {
b.Log.Errorf("Could not retrieve channel members: %#v", err)
return
}
continue
}
newChannelMembers[channels[i].ID] = members
}

if nextCursor == "" {
break
}
Expand All @@ -178,6 +194,10 @@ func (b *Bslack) populateChannels(wait bool) {
b.channelsByID = newChannelsByID
b.channelsByName = newChannelsByName

b.channelMembersMutex.Lock()
defer b.channelMembersMutex.Unlock()
b.channelMembers = newChannelMembers

b.refreshMutex.Lock()
defer b.refreshMutex.Unlock()
b.earliestChannelRefresh = time.Now().Add(minimumRefreshInterval)
Expand Down Expand Up @@ -362,3 +382,29 @@ func (b *Bslack) handleRateLimit(err error) error {
time.Sleep(rateLimit.RetryAfter)
return nil
}

// getUsersInConversation returns an array of userIDs that are members of channelID
func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) {
channelMembers := []string{}
for {
queryParams := &slack.GetUsersInConversationParameters{
ChannelID: channelID,
}

members, nextCursor, err := b.sc.GetUsersInConversation(queryParams)
if err != nil {
if err = b.handleRateLimit(err); err != nil {
return channelMembers, fmt.Errorf("Could not retrieve users in channels: %#v", err)
}
continue
}

channelMembers = append(channelMembers, members...)

if nextCursor == "" {
break
}
queryParams.Cursor = nextCursor
}
return channelMembers, nil
}
8 changes: 8 additions & 0 deletions bridge/slack/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type Bslack struct {
channelsByName map[string]*slack.Channel
channelsMutex sync.RWMutex

channelMembers map[string][]string
channelMembersMutex sync.RWMutex

refreshInProgress bool
earliestChannelRefresh time.Time
earliestUserRefresh time.Time
Expand Down Expand Up @@ -265,6 +268,11 @@ func (b *Bslack) sendWebhook(msg config.Message) error {
}

func (b *Bslack) sendRTM(msg config.Message) (string, error) {
// Handle channelmember messages.
if handled := b.handleGetChannelMembers(&msg); handled {
return "", nil
}

channelInfo, err := b.getChannel(msg.Channel)
if err != nil {
return "", fmt.Errorf("could not send message: %v", err)
Expand Down

0 comments on commit b936afd

Please sign in to comment.