diff options
Diffstat (limited to 'bridge/discord/helpers.go')
-rw-r--r-- | bridge/discord/helpers.go | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/bridge/discord/helpers.go b/bridge/discord/helpers.go new file mode 100644 index 00000000..e693498c --- /dev/null +++ b/bridge/discord/helpers.go @@ -0,0 +1,189 @@ +package bdiscord + +import ( + "errors" + "regexp" + "strings" + "unicode" + + "github.com/bwmarrin/discordgo" +) + +func (b *Bdiscord) getNick(user *discordgo.User) string { + b.membersMutex.RLock() + defer b.membersMutex.RUnlock() + + if member, ok := b.userMemberMap[user.ID]; ok { + if member.Nick != "" { + // Only return if nick is set. + return member.Nick + } + // Otherwise return username. + return user.Username + } + + // If we didn't find nick, search for it. + member, err := b.c.GuildMember(b.guildID, user.ID) + if err != nil { + b.Log.Warnf("Failed to fetch information for member %#v: %#v", user, err) + return user.Username + } else if member == nil { + b.Log.Warnf("Got no information for member %#v", user) + return user.Username + } + b.userMemberMap[user.ID] = member + b.nickMemberMap[member.User.Username] = member + if member.Nick != "" { + b.nickMemberMap[member.Nick] = member + return member.Nick + } + return user.Username +} + +func (b *Bdiscord) getGuildMemberByNick(nick string) (*discordgo.Member, error) { + b.membersMutex.RLock() + defer b.membersMutex.RUnlock() + + if member, ok := b.nickMemberMap[nick]; ok { + return member, nil + } + return nil, errors.New("Couldn't find guild member with nick " + nick) // This will most likely get ignored by the caller +} + +func (b *Bdiscord) getChannelID(name string) string { + b.channelsMutex.RLock() + defer b.channelsMutex.RUnlock() + + idcheck := strings.Split(name, "ID:") + if len(idcheck) > 1 { + return idcheck[1] + } + for _, channel := range b.channels { + if channel.Name == name { + return channel.ID + } + } + return "" +} + +func (b *Bdiscord) getChannelName(id string) string { + b.channelsMutex.RLock() + defer b.channelsMutex.RUnlock() + + for _, channel := range b.channels { + if channel.ID == id { + return channel.Name + } + } + return "" +} + +var ( + // See https://discordapp.com/developers/docs/reference#message-formatting. + channelMentionRE = regexp.MustCompile("<#[0-9]+>") + emojiRE = regexp.MustCompile("<(:.*?:)[0-9]+>") + userMentionRE = regexp.MustCompile("@[^@\n]{1,32}") +) + +func (b *Bdiscord) replaceChannelMentions(text string) string { + replaceChannelMentionFunc := func(match string) string { + var err error + channelID := match[2 : len(match)-1] + + channelName := b.getChannelName(channelID) + // If we don't have the channel refresh our list. + if channelName == "" { + b.channels, err = b.c.GuildChannels(b.guildID) + if err != nil { + return "#unknownchannel" + } + channelName = b.getChannelName(channelID) + } + return "#" + channelName + } + return channelMentionRE.ReplaceAllStringFunc(text, replaceChannelMentionFunc) +} + +func (b *Bdiscord) replaceUserMentions(text string) string { + replaceUserMentionFunc := func(match string) string { + var ( + err error + member *discordgo.Member + username string + ) + + usernames := enumerateUsernames(match[1:]) + for _, username = range usernames { + b.Log.Debugf("Testing mention: '%s'", username) + member, err = b.getGuildMemberByNick(username) + if err == nil { + break + } + } + if member == nil { + return match + } + return strings.Replace(match, "@"+username, member.User.Mention(), 1) + } + return userMentionRE.ReplaceAllStringFunc(text, replaceUserMentionFunc) +} + +func (b *Bdiscord) stripCustomoji(text string) string { + return emojiRE.ReplaceAllString(text, `$1`) +} + +func (b *Bdiscord) replaceAction(text string) (string, bool) { + if strings.HasPrefix(text, "_") && strings.HasSuffix(text, "_") { + return text[1:], true + } + return text, false +} + +// splitURL splits a webhookURL and returns the ID and token. +func (b *Bdiscord) splitURL(url string) (string, string) { + const ( + expectedWebhookSplitCount = 7 + webhookIdxID = 5 + webhookIdxToken = 6 + ) + webhookURLSplit := strings.Split(url, "/") + if len(webhookURLSplit) != expectedWebhookSplitCount { + b.Log.Fatalf("%s is no correct discord WebhookURL", url) + } + return webhookURLSplit[webhookIdxID], webhookURLSplit[webhookIdxToken] +} + +func enumerateUsernames(s string) []string { + onlySpace := true + for _, r := range s { + if !unicode.IsSpace(r) { + onlySpace = false + break + } + } + if onlySpace { + return nil + } + + var username, endSpace string + var usernames []string + skippingSpace := true + for _, r := range s { + if unicode.IsSpace(r) { + if !skippingSpace { + usernames = append(usernames, username) + skippingSpace = true + } + endSpace += string(r) + username += string(r) + } else { + endSpace = "" + username += string(r) + skippingSpace = false + } + } + if endSpace == "" { + usernames = append(usernames, username) + } + return usernames +} |