5
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2024-11-23 01:11:37 +00:00
matterbridge/bridge/slack/helpers.go
2018-11-01 21:28:22 +01:00

196 lines
5.1 KiB
Go

package bslack
import (
"fmt"
"regexp"
"strings"
"sync"
"time"
"github.com/nlopes/slack"
)
func (b *Bslack) getUsername(id string) string {
for _, u := range b.users {
if u.ID == id {
if u.Profile.DisplayName != "" {
return u.Profile.DisplayName
}
return u.Name
}
}
b.Log.Warnf("Could not find user with ID '%s'", id)
return ""
}
func (b *Bslack) getAvatar(userid string) string {
for _, u := range b.users {
if userid == u.ID {
return u.Profile.Image48
}
}
return ""
}
func (b *Bslack) getChannel(channel string) (*slack.Channel, error) {
if strings.HasPrefix(channel, "ID:") {
return b.getChannelByID(strings.TrimPrefix(channel, "ID:"))
}
return b.getChannelByName(channel)
}
func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) {
b.channelsMutex.RLock()
defer b.channelsMutex.RUnlock()
if channel, ok := b.channelsByName[name]; ok {
return channel, nil
}
return nil, fmt.Errorf("%s: channel %s not found", b.Account, name)
}
func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) {
b.channelsMutex.RLock()
defer b.channelsMutex.RUnlock()
if channel, ok := b.channelsByID[ID]; ok {
return channel, nil
}
return nil, fmt.Errorf("%s: channel %s not found", b.Account, ID)
}
const minimumRefreshInterval = 10 * time.Second
var (
refreshMutex sync.Mutex
refreshInProgress bool
earliestChannelRefresh = time.Now()
earliestUserRefresh = time.Now()
)
func (b *Bslack) populateUsers() {
refreshMutex.Lock()
if time.Now().Before(earliestUserRefresh) || refreshInProgress {
b.Log.Debugf("Not refreshing user list as it was done less than %d seconds ago.", int(minimumRefreshInterval.Seconds()))
refreshMutex.Unlock()
return
}
refreshInProgress = true
refreshMutex.Unlock()
users, err := b.sc.GetUsers()
if err != nil {
b.Log.Errorf("Could not reload users: %#v", err)
return
}
newUsers := map[string]*slack.User{}
for i := range users {
// Use array index for pointer, not the copy
// See: https://stackoverflow.com/a/29498133/504018
newUsers[users[i].ID] = &users[i]
}
b.usersMutex.Lock()
defer b.usersMutex.Unlock()
b.users = newUsers
earliestUserRefresh = time.Now().Add(minimumRefreshInterval)
refreshInProgress = false
}
func (b *Bslack) populateChannels() {
refreshMutex.Lock()
if time.Now().Before(earliestChannelRefresh) || refreshInProgress {
b.Log.Debugf("Not refreshing channel list as it was done less than %d seconds ago.", int(minimumRefreshInterval.Seconds()))
refreshMutex.Unlock()
return
}
refreshInProgress = true
refreshMutex.Unlock()
newChannelsByID := map[string]*slack.Channel{}
newChannelsByName := map[string]*slack.Channel{}
// We only retrieve public and private channels, not IMs
// and MPIMs as those do not have a channel name.
queryParams := &slack.GetConversationsParameters{
ExcludeArchived: "true",
Types: []string{"public_channel,private_channel"},
}
for {
channels, nextCursor, err := b.sc.GetConversations(queryParams)
if err != nil {
b.Log.Errorf("Could not reload channels: %#v", err)
return
}
for i := 0; i < len(channels); i++ {
newChannelsByID[channels[i].ID] = &channels[i]
newChannelsByName[channels[i].Name] = &channels[i]
}
if nextCursor == "" {
break
}
queryParams.Cursor = nextCursor
}
b.channelsMutex.Lock()
defer b.channelsMutex.Unlock()
b.channelsByID = newChannelsByID
b.channelsByName = newChannelsByName
earliestChannelRefresh = time.Now().Add(minimumRefreshInterval)
refreshInProgress = false
}
var (
mentionRE = regexp.MustCompile(`<@([a-zA-Z0-9]+)>`)
channelRE = regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`)
variableRE = regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`)
urlRE = regexp.MustCompile(`<(.*?)(\|.*?)?>`)
)
// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (b *Bslack) replaceMention(text string) string {
replaceFunc := func(match string) string {
userID := strings.Trim(match, "@<>")
if username := b.getUsername(userID); userID != "" {
return "@" + username
}
return match
}
return mentionRE.ReplaceAllStringFunc(text, replaceFunc)
}
// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (b *Bslack) replaceChannel(text string) string {
for _, r := range channelRE.FindAllStringSubmatch(text, -1) {
text = strings.Replace(text, r[0], "#"+r[1], 1)
}
return text
}
// @see https://api.slack.com/docs/message-formatting#variables
func (b *Bslack) replaceVariable(text string) string {
for _, r := range variableRE.FindAllStringSubmatch(text, -1) {
if r[2] != "" {
text = strings.Replace(text, r[0], "@"+r[2], 1)
} else {
text = strings.Replace(text, r[0], "@"+r[1], 1)
}
}
return text
}
// @see https://api.slack.com/docs/message-formatting#linking_to_urls
func (b *Bslack) replaceURL(text string) string {
for _, r := range urlRE.FindAllStringSubmatch(text, -1) {
if len(strings.TrimSpace(r[2])) == 1 { // A display text separator was found, but the text was blank
text = strings.Replace(text, r[0], "", 1)
} else {
text = strings.Replace(text, r[0], r[1], 1)
}
}
return text
}