mirror of
https://github.com/cwinfo/matterbridge.git
synced 2024-11-22 14:00:27 +00:00
Update vendor (bwmarrin/discordgo) apiv6
This commit is contained in:
parent
812db2d267
commit
49204cafcc
3
vendor/github.com/bwmarrin/discordgo/discord.go
generated
vendored
3
vendor/github.com/bwmarrin/discordgo/discord.go
generated
vendored
@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
|
||||
const VERSION = "0.16.0"
|
||||
const VERSION = "0.17.0"
|
||||
|
||||
// ErrMFA will be risen by New when the user has 2FA.
|
||||
var ErrMFA = errors.New("account has 2FA enabled")
|
||||
@ -59,6 +59,7 @@ func New(args ...interface{}) (s *Session, err error) {
|
||||
MaxRestRetries: 3,
|
||||
Client: &http.Client{Timeout: (20 * time.Second)},
|
||||
sequence: new(int64),
|
||||
LastHeartbeatAck: time.Now().UTC(),
|
||||
}
|
||||
|
||||
// If no arguments are passed return the empty Session interface.
|
||||
|
42
vendor/github.com/bwmarrin/discordgo/endpoints.go
generated
vendored
42
vendor/github.com/bwmarrin/discordgo/endpoints.go
generated
vendored
@ -11,6 +11,9 @@
|
||||
|
||||
package discordgo
|
||||
|
||||
// APIVersion is the Discord API version used for the REST and Websocket API.
|
||||
var APIVersion = "6"
|
||||
|
||||
// Known Discord API Endpoints.
|
||||
var (
|
||||
EndpointStatus = "https://status.discordapp.com/api/v2/"
|
||||
@ -18,13 +21,14 @@ var (
|
||||
EndpointSmActive = EndpointSm + "active.json"
|
||||
EndpointSmUpcoming = EndpointSm + "upcoming.json"
|
||||
|
||||
EndpointDiscord = "https://discordapp.com/"
|
||||
EndpointAPI = EndpointDiscord + "api/"
|
||||
EndpointGuilds = EndpointAPI + "guilds/"
|
||||
EndpointChannels = EndpointAPI + "channels/"
|
||||
EndpointUsers = EndpointAPI + "users/"
|
||||
EndpointGateway = EndpointAPI + "gateway"
|
||||
EndpointWebhooks = EndpointAPI + "webhooks/"
|
||||
EndpointDiscord = "https://discordapp.com/"
|
||||
EndpointAPI = EndpointDiscord + "api/v" + APIVersion + "/"
|
||||
EndpointGuilds = EndpointAPI + "guilds/"
|
||||
EndpointChannels = EndpointAPI + "channels/"
|
||||
EndpointUsers = EndpointAPI + "users/"
|
||||
EndpointGateway = EndpointAPI + "gateway"
|
||||
EndpointGatewayBot = EndpointGateway + "/bot"
|
||||
EndpointWebhooks = EndpointAPI + "webhooks/"
|
||||
|
||||
EndpointCDN = "https://cdn.discordapp.com/"
|
||||
EndpointCDNAttachments = EndpointCDN + "attachments/"
|
||||
@ -54,16 +58,17 @@ var (
|
||||
EndpointReport = EndpointAPI + "report"
|
||||
EndpointIntegrations = EndpointAPI + "integrations"
|
||||
|
||||
EndpointUser = func(uID string) string { return EndpointUsers + uID }
|
||||
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
|
||||
EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
|
||||
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
|
||||
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
|
||||
EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
|
||||
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
|
||||
EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
|
||||
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
|
||||
EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
|
||||
EndpointUser = func(uID string) string { return EndpointUsers + uID }
|
||||
EndpointUserAvatar = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" }
|
||||
EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" }
|
||||
EndpointUserSettings = func(uID string) string { return EndpointUsers + uID + "/settings" }
|
||||
EndpointUserGuilds = func(uID string) string { return EndpointUsers + uID + "/guilds" }
|
||||
EndpointUserGuild = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID }
|
||||
EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" }
|
||||
EndpointUserChannels = func(uID string) string { return EndpointUsers + uID + "/channels" }
|
||||
EndpointUserDevices = func(uID string) string { return EndpointUsers + uID + "/devices" }
|
||||
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }
|
||||
EndpointUserNotes = func(uID string) string { return EndpointUsers + "@me/notes/" + uID }
|
||||
|
||||
EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
|
||||
EndpointGuildInivtes = func(gID string) string { return EndpointGuilds + gID + "/invites" }
|
||||
@ -103,6 +108,9 @@ var (
|
||||
EndpointWebhook = func(wID string) string { return EndpointWebhooks + wID }
|
||||
EndpointWebhookToken = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token }
|
||||
|
||||
EndpointMessageReactionsAll = func(cID, mID string) string {
|
||||
return EndpointChannelMessage(cID, mID) + "/reactions"
|
||||
}
|
||||
EndpointMessageReactions = func(cID, mID, eID string) string {
|
||||
return EndpointChannelMessage(cID, mID) + "/reactions/" + eID
|
||||
}
|
||||
|
14
vendor/github.com/bwmarrin/discordgo/event.go
generated
vendored
14
vendor/github.com/bwmarrin/discordgo/event.go
generated
vendored
@ -156,12 +156,20 @@ func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance
|
||||
// Handles calling permanent and once handlers for an event type.
|
||||
func (s *Session) handle(t string, i interface{}) {
|
||||
for _, eh := range s.handlers[t] {
|
||||
go eh.eventHandler.Handle(s, i)
|
||||
if s.SyncEvents {
|
||||
eh.eventHandler.Handle(s, i)
|
||||
} else {
|
||||
go eh.eventHandler.Handle(s, i)
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.onceHandlers[t]) > 0 {
|
||||
for _, eh := range s.onceHandlers[t] {
|
||||
go eh.eventHandler.Handle(s, i)
|
||||
if s.SyncEvents {
|
||||
eh.eventHandler.Handle(s, i)
|
||||
} else {
|
||||
go eh.eventHandler.Handle(s, i)
|
||||
}
|
||||
}
|
||||
s.onceHandlers[t] = nil
|
||||
}
|
||||
@ -216,7 +224,7 @@ func (s *Session) onInterface(i interface{}) {
|
||||
case *VoiceStateUpdate:
|
||||
go s.onVoiceStateUpdate(t)
|
||||
}
|
||||
err := s.State.onInterface(s, i)
|
||||
err := s.State.OnInterface(s, i)
|
||||
if err != nil {
|
||||
s.log(LogDebug, "error dispatching internal event, %s", err)
|
||||
}
|
||||
|
94
vendor/github.com/bwmarrin/discordgo/message.go
generated
vendored
94
vendor/github.com/bwmarrin/discordgo/message.go
generated
vendored
@ -10,9 +10,24 @@
|
||||
package discordgo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MessageType is the type of Message
|
||||
type MessageType int
|
||||
|
||||
// Block contains the valid known MessageType values
|
||||
const (
|
||||
MessageTypeDefault MessageType = iota
|
||||
MessageTypeRecipientAdd
|
||||
MessageTypeRecipientRemove
|
||||
MessageTypeCall
|
||||
MessageTypeChannelNameChange
|
||||
MessageTypeChannelIconChange
|
||||
MessageTypeChannelPinnedMessage
|
||||
MessageTypeGuildMemberJoin
|
||||
)
|
||||
|
||||
// A Message stores all data related to a specific Discord message.
|
||||
@ -30,12 +45,14 @@ type Message struct {
|
||||
Embeds []*MessageEmbed `json:"embeds"`
|
||||
Mentions []*User `json:"mentions"`
|
||||
Reactions []*MessageReactions `json:"reactions"`
|
||||
Type MessageType `json:"type"`
|
||||
}
|
||||
|
||||
// File stores info about files you e.g. send in messages.
|
||||
type File struct {
|
||||
Name string
|
||||
Reader io.Reader
|
||||
Name string
|
||||
ContentType string
|
||||
Reader io.Reader
|
||||
}
|
||||
|
||||
// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
|
||||
@ -43,7 +60,10 @@ type MessageSend struct {
|
||||
Content string `json:"content,omitempty"`
|
||||
Embed *MessageEmbed `json:"embed,omitempty"`
|
||||
Tts bool `json:"tts"`
|
||||
File *File `json:"file"`
|
||||
Files []*File `json:"-"`
|
||||
|
||||
// TODO: Remove this when compatibility is not required.
|
||||
File *File `json:"-"`
|
||||
}
|
||||
|
||||
// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
|
||||
@ -168,13 +188,65 @@ type MessageReactions struct {
|
||||
|
||||
// ContentWithMentionsReplaced will replace all @<id> mentions with the
|
||||
// username of the mention.
|
||||
func (m *Message) ContentWithMentionsReplaced() string {
|
||||
if m.Mentions == nil {
|
||||
return m.Content
|
||||
}
|
||||
content := m.Content
|
||||
func (m *Message) ContentWithMentionsReplaced() (content string) {
|
||||
content = m.Content
|
||||
|
||||
for _, user := range m.Mentions {
|
||||
content = regexp.MustCompile(fmt.Sprintf("<@!?(%s)>", user.ID)).ReplaceAllString(content, "@"+user.Username)
|
||||
content = strings.NewReplacer(
|
||||
"<@"+user.ID+">", "@"+user.Username,
|
||||
"<@!"+user.ID+">", "@"+user.Username,
|
||||
).Replace(content)
|
||||
}
|
||||
return content
|
||||
return
|
||||
}
|
||||
|
||||
var patternChannels = regexp.MustCompile("<#[^>]*>")
|
||||
|
||||
// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
|
||||
// username of the mention, but also role IDs and more.
|
||||
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
|
||||
content = m.Content
|
||||
|
||||
if !s.StateEnabled {
|
||||
content = m.ContentWithMentionsReplaced()
|
||||
return
|
||||
}
|
||||
|
||||
channel, err := s.State.Channel(m.ChannelID)
|
||||
if err != nil {
|
||||
content = m.ContentWithMentionsReplaced()
|
||||
return
|
||||
}
|
||||
|
||||
for _, user := range m.Mentions {
|
||||
nick := user.Username
|
||||
|
||||
member, err := s.State.Member(channel.GuildID, user.ID)
|
||||
if err == nil && member.Nick != "" {
|
||||
nick = member.Nick
|
||||
}
|
||||
|
||||
content = strings.NewReplacer(
|
||||
"<@"+user.ID+">", "@"+user.Username,
|
||||
"<@!"+user.ID+">", "@"+nick,
|
||||
).Replace(content)
|
||||
}
|
||||
for _, roleID := range m.MentionRoles {
|
||||
role, err := s.State.Role(channel.GuildID, roleID)
|
||||
if err != nil || !role.Mentionable {
|
||||
continue
|
||||
}
|
||||
|
||||
content = strings.Replace(content, "<&"+role.ID+">", "@"+role.Name, -1)
|
||||
}
|
||||
|
||||
content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
|
||||
channel, err := s.State.Channel(mention[2 : len(mention)-1])
|
||||
if err != nil || channel.Type == ChannelTypeGuildVoice {
|
||||
return mention
|
||||
}
|
||||
|
||||
return "#" + channel.Name
|
||||
})
|
||||
return
|
||||
}
|
||||
|
47
vendor/github.com/bwmarrin/discordgo/ratelimit.go
generated
vendored
47
vendor/github.com/bwmarrin/discordgo/ratelimit.go
generated
vendored
@ -3,17 +3,26 @@ package discordgo
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// customRateLimit holds information for defining a custom rate limit
|
||||
type customRateLimit struct {
|
||||
suffix string
|
||||
requests int
|
||||
reset time.Duration
|
||||
}
|
||||
|
||||
// RateLimiter holds all ratelimit buckets
|
||||
type RateLimiter struct {
|
||||
sync.Mutex
|
||||
global *int64
|
||||
buckets map[string]*Bucket
|
||||
globalRateLimit time.Duration
|
||||
global *int64
|
||||
buckets map[string]*Bucket
|
||||
globalRateLimit time.Duration
|
||||
customRateLimits []*customRateLimit
|
||||
}
|
||||
|
||||
// NewRatelimiter returns a new RateLimiter
|
||||
@ -22,6 +31,13 @@ func NewRatelimiter() *RateLimiter {
|
||||
return &RateLimiter{
|
||||
buckets: make(map[string]*Bucket),
|
||||
global: new(int64),
|
||||
customRateLimits: []*customRateLimit{
|
||||
&customRateLimit{
|
||||
suffix: "//reactions//",
|
||||
requests: 1,
|
||||
reset: 200 * time.Millisecond,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +56,14 @@ func (r *RateLimiter) getBucket(key string) *Bucket {
|
||||
global: r.global,
|
||||
}
|
||||
|
||||
// Check if there is a custom ratelimit set for this bucket ID.
|
||||
for _, rl := range r.customRateLimits {
|
||||
if strings.HasSuffix(b.Key, rl.suffix) {
|
||||
b.customRateLimit = rl
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
r.buckets[key] = b
|
||||
return b
|
||||
}
|
||||
@ -76,13 +100,28 @@ type Bucket struct {
|
||||
limit int
|
||||
reset time.Time
|
||||
global *int64
|
||||
|
||||
lastReset time.Time
|
||||
customRateLimit *customRateLimit
|
||||
}
|
||||
|
||||
// Release unlocks the bucket and reads the headers to update the buckets ratelimit info
|
||||
// and locks up the whole thing in case if there's a global ratelimit.
|
||||
func (b *Bucket) Release(headers http.Header) error {
|
||||
|
||||
defer b.Unlock()
|
||||
|
||||
// Check if the bucket uses a custom ratelimiter
|
||||
if rl := b.customRateLimit; rl != nil {
|
||||
if time.Now().Sub(b.lastReset) >= rl.reset {
|
||||
b.remaining = rl.requests - 1
|
||||
b.lastReset = time.Now()
|
||||
}
|
||||
if b.remaining < 1 {
|
||||
b.reset = time.Now().Add(rl.reset)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if headers == nil {
|
||||
return nil
|
||||
}
|
||||
|
138
vendor/github.com/bwmarrin/discordgo/restapi.go
generated
vendored
138
vendor/github.com/bwmarrin/discordgo/restapi.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
||||
"log"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -309,8 +310,8 @@ func (s *Session) UserUpdate(email, password, username, avatar, newPassword stri
|
||||
// If left blank, avatar will be set to null/blank
|
||||
|
||||
data := struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
Email string `json:"email,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
NewPassword string `json:"new_password,omitempty"`
|
||||
@ -763,7 +764,21 @@ func (s *Session) GuildMember(guildID, userID string) (st *Member, err error) {
|
||||
// userID : The ID of a User
|
||||
func (s *Session) GuildMemberDelete(guildID, userID string) (err error) {
|
||||
|
||||
_, err = s.RequestWithBucketID("DELETE", EndpointGuildMember(guildID, userID), nil, EndpointGuildMember(guildID, ""))
|
||||
return s.GuildMemberDeleteWithReason(guildID, userID, "")
|
||||
}
|
||||
|
||||
// GuildMemberDeleteWithReason removes the given user from the given guild.
|
||||
// guildID : The ID of a Guild.
|
||||
// userID : The ID of a User
|
||||
// reason : The reason for the kick
|
||||
func (s *Session) GuildMemberDeleteWithReason(guildID, userID, reason string) (err error) {
|
||||
|
||||
uri := EndpointGuildMember(guildID, userID)
|
||||
if reason != "" {
|
||||
uri += "?reason=" + url.QueryEscape(reason)
|
||||
}
|
||||
|
||||
_, err = s.RequestWithBucketID("DELETE", uri, nil, EndpointGuildMember(guildID, ""))
|
||||
return
|
||||
}
|
||||
|
||||
@ -1316,6 +1331,8 @@ func (s *Session) ChannelMessageSend(channelID string, content string) (*Message
|
||||
})
|
||||
}
|
||||
|
||||
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
|
||||
|
||||
// ChannelMessageSendComplex sends a message to the given channel.
|
||||
// channelID : The ID of a Channel.
|
||||
// data : The message struct to send.
|
||||
@ -1326,48 +1343,62 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend)
|
||||
|
||||
endpoint := EndpointChannelMessages(channelID)
|
||||
|
||||
var response []byte
|
||||
// TODO: Remove this when compatibility is not required.
|
||||
files := data.Files
|
||||
if data.File != nil {
|
||||
if files == nil {
|
||||
files = []*File{data.File}
|
||||
} else {
|
||||
err = fmt.Errorf("cannot specify both File and Files")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var response []byte
|
||||
if len(files) > 0 {
|
||||
body := &bytes.Buffer{}
|
||||
bodywriter := multipart.NewWriter(body)
|
||||
|
||||
// What's a better way of doing this? Reflect? Generator? I'm open to suggestions
|
||||
|
||||
if data.Content != "" {
|
||||
if err = bodywriter.WriteField("content", data.Content); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if data.Embed != nil {
|
||||
var embed []byte
|
||||
embed, err = json.Marshal(data.Embed)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = bodywriter.WriteField("embed", string(embed))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if data.Tts {
|
||||
if err = bodywriter.WriteField("tts", "true"); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var writer io.Writer
|
||||
writer, err = bodywriter.CreateFormFile("file", data.File.Name)
|
||||
var payload []byte
|
||||
payload, err = json.Marshal(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = io.Copy(writer, data.File.Reader)
|
||||
var p io.Writer
|
||||
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition", `form-data; name="payload_json"`)
|
||||
h.Set("Content-Type", "application/json")
|
||||
|
||||
p, err = bodywriter.CreatePart(h)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = p.Write(payload); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, file := range files {
|
||||
h := make(textproto.MIMEHeader)
|
||||
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file%d"; filename="%s"`, i, quoteEscaper.Replace(file.Name)))
|
||||
contentType := file.ContentType
|
||||
if contentType == "" {
|
||||
contentType = "application/octet-stream"
|
||||
}
|
||||
h.Set("Content-Type", contentType)
|
||||
|
||||
p, err = bodywriter.CreatePart(h)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(p, file.Reader); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = bodywriter.Close()
|
||||
if err != nil {
|
||||
return
|
||||
@ -1685,6 +1716,28 @@ func (s *Session) Gateway() (gateway string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// GatewayBot returns the websocket Gateway address and the recommended number of shards
|
||||
func (s *Session) GatewayBot() (st *GatewayBotResponse, err error) {
|
||||
|
||||
response, err := s.RequestWithBucketID("GET", EndpointGatewayBot, nil, EndpointGatewayBot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(response, &st)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure the gateway always has a trailing slash.
|
||||
// MacOS will fail to connect if we add query params without a trailing slash on the base domain.
|
||||
if !strings.HasSuffix(st.URL, "/") {
|
||||
st.URL += "/"
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Functions specific to Webhooks
|
||||
|
||||
// WebhookCreate returns a new Webhook.
|
||||
@ -1810,14 +1863,9 @@ func (s *Session) WebhookEditWithToken(webhookID, token, name, avatar string) (s
|
||||
|
||||
// WebhookDelete deletes a webhook for a given ID
|
||||
// webhookID: The ID of a webhook.
|
||||
func (s *Session) WebhookDelete(webhookID string) (st *Webhook, err error) {
|
||||
func (s *Session) WebhookDelete(webhookID string) (err error) {
|
||||
|
||||
body, err := s.RequestWithBucketID("DELETE", EndpointWebhook(webhookID), nil, EndpointWebhooks)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = unmarshal(body, &st)
|
||||
_, err = s.RequestWithBucketID("DELETE", EndpointWebhook(webhookID), nil, EndpointWebhooks)
|
||||
|
||||
return
|
||||
}
|
||||
@ -1875,6 +1923,16 @@ func (s *Session) MessageReactionRemove(channelID, messageID, emojiID, userID st
|
||||
return err
|
||||
}
|
||||
|
||||
// MessageReactionsRemoveAll deletes all reactions from a message
|
||||
// channelID : The channel ID
|
||||
// messageID : The message ID.
|
||||
func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error {
|
||||
|
||||
_, err := s.RequestWithBucketID("DELETE", EndpointMessageReactionsAll(channelID, messageID), nil, EndpointMessageReactionsAll(channelID, messageID))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// MessageReactions gets all the users reactions for a specific emoji.
|
||||
// channelID : The channel ID.
|
||||
// messageID : The message ID.
|
||||
|
72
vendor/github.com/bwmarrin/discordgo/state.go
generated
vendored
72
vendor/github.com/bwmarrin/discordgo/state.go
generated
vendored
@ -42,6 +42,7 @@ type State struct {
|
||||
|
||||
guildMap map[string]*Guild
|
||||
channelMap map[string]*Channel
|
||||
memberMap map[string]map[string]*Member
|
||||
}
|
||||
|
||||
// NewState creates an empty state.
|
||||
@ -59,9 +60,18 @@ func NewState() *State {
|
||||
TrackPresences: true,
|
||||
guildMap: make(map[string]*Guild),
|
||||
channelMap: make(map[string]*Channel),
|
||||
memberMap: make(map[string]map[string]*Member),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) createMemberMap(guild *Guild) {
|
||||
members := make(map[string]*Member)
|
||||
for _, m := range guild.Members {
|
||||
members[m.User.ID] = m
|
||||
}
|
||||
s.memberMap[guild.ID] = members
|
||||
}
|
||||
|
||||
// GuildAdd adds a guild to the current world state, or
|
||||
// updates it if it already exists.
|
||||
func (s *State) GuildAdd(guild *Guild) error {
|
||||
@ -77,6 +87,14 @@ func (s *State) GuildAdd(guild *Guild) error {
|
||||
s.channelMap[c.ID] = c
|
||||
}
|
||||
|
||||
// If this guild contains a new member slice, we must regenerate the member map so the pointers stay valid
|
||||
if guild.Members != nil {
|
||||
s.createMemberMap(guild)
|
||||
} else if _, ok := s.memberMap[guild.ID]; !ok {
|
||||
// Even if we have no new member slice, we still initialize the member map for this guild if it doesn't exist
|
||||
s.memberMap[guild.ID] = make(map[string]*Member)
|
||||
}
|
||||
|
||||
if g, ok := s.guildMap[guild.ID]; ok {
|
||||
// We are about to replace `g` in the state with `guild`, but first we need to
|
||||
// make sure we preserve any fields that the `guild` doesn't contain from `g`.
|
||||
@ -271,14 +289,19 @@ func (s *State) MemberAdd(member *Member) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
for i, m := range guild.Members {
|
||||
if m.User.ID == member.User.ID {
|
||||
guild.Members[i] = member
|
||||
return nil
|
||||
}
|
||||
members, ok := s.memberMap[member.GuildID]
|
||||
if !ok {
|
||||
return ErrStateNotFound
|
||||
}
|
||||
|
||||
m, ok := members[member.User.ID]
|
||||
if !ok {
|
||||
members[member.User.ID] = member
|
||||
guild.Members = append(guild.Members, member)
|
||||
} else {
|
||||
*m = *member // Update the actual data, which will also update the member pointer in the slice
|
||||
}
|
||||
|
||||
guild.Members = append(guild.Members, member)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -296,6 +319,17 @@ func (s *State) MemberRemove(member *Member) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
members, ok := s.memberMap[member.GuildID]
|
||||
if !ok {
|
||||
return ErrStateNotFound
|
||||
}
|
||||
|
||||
_, ok = members[member.User.ID]
|
||||
if !ok {
|
||||
return ErrStateNotFound
|
||||
}
|
||||
delete(members, member.User.ID)
|
||||
|
||||
for i, m := range guild.Members {
|
||||
if m.User.ID == member.User.ID {
|
||||
guild.Members = append(guild.Members[:i], guild.Members[i+1:]...)
|
||||
@ -312,18 +346,17 @@ func (s *State) Member(guildID, userID string) (*Member, error) {
|
||||
return nil, ErrNilState
|
||||
}
|
||||
|
||||
guild, err := s.Guild(guildID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
|
||||
for _, m := range guild.Members {
|
||||
if m.User.ID == userID {
|
||||
return m, nil
|
||||
}
|
||||
members, ok := s.memberMap[guildID]
|
||||
if !ok {
|
||||
return nil, ErrStateNotFound
|
||||
}
|
||||
|
||||
m, ok := members[userID]
|
||||
if ok {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
return nil, ErrStateNotFound
|
||||
@ -427,7 +460,7 @@ func (s *State) ChannelAdd(channel *Channel) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if channel.IsPrivate {
|
||||
if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM {
|
||||
s.PrivateChannels = append(s.PrivateChannels, channel)
|
||||
} else {
|
||||
guild, ok := s.guildMap[channel.GuildID]
|
||||
@ -454,7 +487,7 @@ func (s *State) ChannelRemove(channel *Channel) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if channel.IsPrivate {
|
||||
if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
@ -735,6 +768,7 @@ func (s *State) onReady(se *Session, r *Ready) (err error) {
|
||||
|
||||
for _, g := range s.Guilds {
|
||||
s.guildMap[g.ID] = g
|
||||
s.createMemberMap(g)
|
||||
|
||||
for _, c := range g.Channels {
|
||||
s.channelMap[c.ID] = c
|
||||
@ -748,8 +782,8 @@ func (s *State) onReady(se *Session, r *Ready) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// onInterface handles all events related to states.
|
||||
func (s *State) onInterface(se *Session, i interface{}) (err error) {
|
||||
// OnInterface handles all events related to states.
|
||||
func (s *State) OnInterface(se *Session, i interface{}) (err error) {
|
||||
if s == nil {
|
||||
return ErrNilState
|
||||
}
|
||||
|
87
vendor/github.com/bwmarrin/discordgo/structs.go
generated
vendored
87
vendor/github.com/bwmarrin/discordgo/structs.go
generated
vendored
@ -50,6 +50,10 @@ type Session struct {
|
||||
// active guilds and the members of the guilds.
|
||||
StateEnabled bool
|
||||
|
||||
// Whether or not to call event handlers synchronously.
|
||||
// e.g false = launch event handlers in their own goroutines.
|
||||
SyncEvents bool
|
||||
|
||||
// Exposed but should not be modified by User.
|
||||
|
||||
// Whether the Data Websocket is ready
|
||||
@ -78,6 +82,9 @@ type Session struct {
|
||||
// The http client used for REST requests
|
||||
Client *http.Client
|
||||
|
||||
// Stores the last HeartbeatAck that was recieved (in UTC)
|
||||
LastHeartbeatAck time.Time
|
||||
|
||||
// Event handlers
|
||||
handlersMu sync.RWMutex
|
||||
handlers map[string][]*eventHandlerInstance
|
||||
@ -141,18 +148,30 @@ type Invite struct {
|
||||
Temporary bool `json:"temporary"`
|
||||
}
|
||||
|
||||
// ChannelType is the type of a Channel
|
||||
type ChannelType int
|
||||
|
||||
// Block contains known ChannelType values
|
||||
const (
|
||||
ChannelTypeGuildText ChannelType = iota
|
||||
ChannelTypeDM
|
||||
ChannelTypeGuildVoice
|
||||
ChannelTypeGroupDM
|
||||
ChannelTypeGuildCategory
|
||||
)
|
||||
|
||||
// A Channel holds all data related to an individual Discord channel.
|
||||
type Channel struct {
|
||||
ID string `json:"id"`
|
||||
GuildID string `json:"guild_id"`
|
||||
Name string `json:"name"`
|
||||
Topic string `json:"topic"`
|
||||
Type string `json:"type"`
|
||||
Type ChannelType `json:"type"`
|
||||
LastMessageID string `json:"last_message_id"`
|
||||
NSFW bool `json:"nsfw"`
|
||||
Position int `json:"position"`
|
||||
Bitrate int `json:"bitrate"`
|
||||
IsPrivate bool `json:"is_private"`
|
||||
Recipient *User `json:"recipient"`
|
||||
Recipients []*User `json:"recipient"`
|
||||
Messages []*Message `json:"-"`
|
||||
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"`
|
||||
}
|
||||
@ -292,13 +311,14 @@ type Presence struct {
|
||||
Game *Game `json:"game"`
|
||||
Nick string `json:"nick"`
|
||||
Roles []string `json:"roles"`
|
||||
Since *int `json:"since"`
|
||||
}
|
||||
|
||||
// A Game struct holds the name of the "playing .." game for a user
|
||||
type Game struct {
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
URL string `json:"url"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals json to Game struct
|
||||
@ -509,6 +529,12 @@ type MessageReaction struct {
|
||||
ChannelID string `json:"channel_id"`
|
||||
}
|
||||
|
||||
// GatewayBotResponse stores the data for the gateway/bot response
|
||||
type GatewayBotResponse struct {
|
||||
URL string `json:"url"`
|
||||
Shards int `json:"shards"`
|
||||
}
|
||||
|
||||
// Constants for the different bit offsets of text channel permissions
|
||||
const (
|
||||
PermissionReadMessages = 1 << (iota + 10)
|
||||
@ -579,3 +605,56 @@ const (
|
||||
PermissionManageServer |
|
||||
PermissionAdministrator
|
||||
)
|
||||
|
||||
// Block contains Discord JSON Error Response codes
|
||||
const (
|
||||
ErrCodeUnknownAccount = 10001
|
||||
ErrCodeUnknownApplication = 10002
|
||||
ErrCodeUnknownChannel = 10003
|
||||
ErrCodeUnknownGuild = 10004
|
||||
ErrCodeUnknownIntegration = 10005
|
||||
ErrCodeUnknownInvite = 10006
|
||||
ErrCodeUnknownMember = 10007
|
||||
ErrCodeUnknownMessage = 10008
|
||||
ErrCodeUnknownOverwrite = 10009
|
||||
ErrCodeUnknownProvider = 10010
|
||||
ErrCodeUnknownRole = 10011
|
||||
ErrCodeUnknownToken = 10012
|
||||
ErrCodeUnknownUser = 10013
|
||||
ErrCodeUnknownEmoji = 10014
|
||||
|
||||
ErrCodeBotsCannotUseEndpoint = 20001
|
||||
ErrCodeOnlyBotsCanUseEndpoint = 20002
|
||||
|
||||
ErrCodeMaximumGuildsReached = 30001
|
||||
ErrCodeMaximumFriendsReached = 30002
|
||||
ErrCodeMaximumPinsReached = 30003
|
||||
ErrCodeMaximumGuildRolesReached = 30005
|
||||
ErrCodeTooManyReactions = 30010
|
||||
|
||||
ErrCodeUnauthorized = 40001
|
||||
|
||||
ErrCodeMissingAccess = 50001
|
||||
ErrCodeInvalidAccountType = 50002
|
||||
ErrCodeCannotExecuteActionOnDMChannel = 50003
|
||||
ErrCodeEmbedCisabled = 50004
|
||||
ErrCodeCannotEditFromAnotherUser = 50005
|
||||
ErrCodeCannotSendEmptyMessage = 50006
|
||||
ErrCodeCannotSendMessagesToThisUser = 50007
|
||||
ErrCodeCannotSendMessagesInVoiceChannel = 50008
|
||||
ErrCodeChannelVerificationLevelTooHigh = 50009
|
||||
ErrCodeOAuth2ApplicationDoesNotHaveBot = 50010
|
||||
ErrCodeOAuth2ApplicationLimitReached = 50011
|
||||
ErrCodeInvalidOAuthState = 50012
|
||||
ErrCodeMissingPermissions = 50013
|
||||
ErrCodeInvalidAuthenticationToken = 50014
|
||||
ErrCodeNoteTooLong = 50015
|
||||
ErrCodeTooFewOrTooManyMessagesToDelete = 50016
|
||||
ErrCodeCanOnlyPinMessageToOriginatingChannel = 50019
|
||||
ErrCodeCannotExecuteActionOnSystemMessage = 50021
|
||||
ErrCodeMessageProvidedTooOldForBulkDelete = 50034
|
||||
ErrCodeInvalidFormBody = 50035
|
||||
ErrCodeInviteAcceptedToGuildApplicationsBotNotIn = 50036
|
||||
|
||||
ErrCodeReactionBlocked = 90001
|
||||
)
|
||||
|
18
vendor/github.com/bwmarrin/discordgo/user.go
generated
vendored
18
vendor/github.com/bwmarrin/discordgo/user.go
generated
vendored
@ -1,6 +1,9 @@
|
||||
package discordgo
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A User stores all data for an individual Discord user.
|
||||
type User struct {
|
||||
@ -24,3 +27,16 @@ func (u *User) String() string {
|
||||
func (u *User) Mention() string {
|
||||
return fmt.Sprintf("<@%s>", u.ID)
|
||||
}
|
||||
|
||||
// AvatarURL returns a URL to the user's avatar.
|
||||
// size: The size of the user's avatar as a power of two
|
||||
func (u *User) AvatarURL(size string) string {
|
||||
var URL string
|
||||
if strings.HasPrefix(u.Avatar, "a_") {
|
||||
URL = EndpointUserAvatarAnimated(u.ID, u.Avatar)
|
||||
} else {
|
||||
URL = EndpointUserAvatar(u.ID, u.Avatar)
|
||||
}
|
||||
|
||||
return URL + "?size=" + size
|
||||
}
|
||||
|
13
vendor/github.com/bwmarrin/discordgo/voice.go
generated
vendored
13
vendor/github.com/bwmarrin/discordgo/voice.go
generated
vendored
@ -796,7 +796,7 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
|
||||
}
|
||||
|
||||
// For now, skip anything except audio.
|
||||
if rlen < 12 || recvbuf[0] != 0x80 {
|
||||
if rlen < 12 || (recvbuf[0] != 0x80 && recvbuf[0] != 0x90) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -810,8 +810,17 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct
|
||||
copy(nonce[:], recvbuf[0:12])
|
||||
p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
|
||||
|
||||
if len(p.Opus) > 8 && recvbuf[0] == 0x90 {
|
||||
// Extension bit is set, first 8 bytes is the extended header
|
||||
p.Opus = p.Opus[8:]
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
c <- &p
|
||||
select {
|
||||
case c <- &p:
|
||||
case <-close:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
58
vendor/github.com/bwmarrin/discordgo/wsapi.go
generated
vendored
58
vendor/github.com/bwmarrin/discordgo/wsapi.go
generated
vendored
@ -15,7 +15,6 @@ import (
|
||||
"compress/zlib"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"runtime"
|
||||
@ -87,7 +86,7 @@ func (s *Session) Open() (err error) {
|
||||
}
|
||||
|
||||
// Add the version and encoding to the URL
|
||||
s.gateway = fmt.Sprintf("%s?v=5&encoding=json", s.gateway)
|
||||
s.gateway = s.gateway + "?v=" + APIVersion + "&encoding=json"
|
||||
}
|
||||
|
||||
header := http.Header{}
|
||||
@ -131,6 +130,7 @@ func (s *Session) Open() (err error) {
|
||||
// lock.
|
||||
s.listening = make(chan interface{})
|
||||
go s.listen(s.wsConn, s.listening)
|
||||
s.LastHeartbeatAck = time.Now().UTC()
|
||||
|
||||
s.Unlock()
|
||||
|
||||
@ -199,10 +199,13 @@ type helloOp struct {
|
||||
Trace []string `json:"_trace"`
|
||||
}
|
||||
|
||||
// FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart.
|
||||
const FailedHeartbeatAcks time.Duration = 5 * time.Millisecond
|
||||
|
||||
// heartbeat sends regular heartbeats to Discord so it knows the client
|
||||
// is still connected. If you do not send these heartbeats Discord will
|
||||
// disconnect the websocket connection after a few seconds.
|
||||
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {
|
||||
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, heartbeatIntervalMsec time.Duration) {
|
||||
|
||||
s.log(LogInformational, "called")
|
||||
|
||||
@ -211,20 +214,26 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}
|
||||
}
|
||||
|
||||
var err error
|
||||
ticker := time.NewTicker(i * time.Millisecond)
|
||||
ticker := time.NewTicker(heartbeatIntervalMsec * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
s.RLock()
|
||||
last := s.LastHeartbeatAck
|
||||
s.RUnlock()
|
||||
sequence := atomic.LoadInt64(s.sequence)
|
||||
s.log(LogInformational, "sending gateway websocket heartbeat seq %d", sequence)
|
||||
s.wsMutex.Lock()
|
||||
err = wsConn.WriteJSON(heartbeatOp{1, sequence})
|
||||
s.wsMutex.Unlock()
|
||||
if err != nil {
|
||||
s.log(LogError, "error sending heartbeat to gateway %s, %s", s.gateway, err)
|
||||
s.Lock()
|
||||
s.DataReady = false
|
||||
s.Unlock()
|
||||
if err != nil || time.Now().UTC().Sub(last) > (heartbeatIntervalMsec*FailedHeartbeatAcks) {
|
||||
if err != nil {
|
||||
s.log(LogError, "error sending heartbeat to gateway %s, %s", s.gateway, err)
|
||||
} else {
|
||||
s.log(LogError, "haven't gotten a heartbeat ACK in %v, triggering a reconnection", time.Now().UTC().Sub(last))
|
||||
}
|
||||
s.Close()
|
||||
s.reconnect()
|
||||
return
|
||||
}
|
||||
s.Lock()
|
||||
@ -241,8 +250,10 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}
|
||||
}
|
||||
|
||||
type updateStatusData struct {
|
||||
IdleSince *int `json:"idle_since"`
|
||||
Game *Game `json:"game"`
|
||||
IdleSince *int `json:"since"`
|
||||
Game *Game `json:"game"`
|
||||
AFK bool `json:"afk"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type updateStatusOp struct {
|
||||
@ -265,7 +276,10 @@ func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err
|
||||
return ErrWSNotFound
|
||||
}
|
||||
|
||||
var usd updateStatusData
|
||||
usd := updateStatusData{
|
||||
Status: "online",
|
||||
}
|
||||
|
||||
if idle > 0 {
|
||||
usd.IdleSince = &idle
|
||||
}
|
||||
@ -398,7 +412,10 @@ func (s *Session) onEvent(messageType int, message []byte) {
|
||||
// Reconnect
|
||||
// Must immediately disconnect from gateway and reconnect to new gateway.
|
||||
if e.Operation == 7 {
|
||||
// TODO
|
||||
s.log(LogInformational, "Closing and reconnecting in response to Op7")
|
||||
s.Close()
|
||||
s.reconnect()
|
||||
return
|
||||
}
|
||||
|
||||
// Invalid Session
|
||||
@ -426,6 +443,14 @@ func (s *Session) onEvent(messageType int, message []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
if e.Operation == 11 {
|
||||
s.Lock()
|
||||
s.LastHeartbeatAck = time.Now().UTC()
|
||||
s.Unlock()
|
||||
s.log(LogInformational, "got heartbeat ACK")
|
||||
return
|
||||
}
|
||||
|
||||
// Do not try to Dispatch a non-Dispatch Message
|
||||
if e.Operation != 0 {
|
||||
// But we probably should be doing something with them.
|
||||
@ -688,6 +713,13 @@ func (s *Session) reconnect() {
|
||||
return
|
||||
}
|
||||
|
||||
// Certain race conditions can call reconnect() twice. If this happens, we
|
||||
// just break out of the reconnect loop
|
||||
if err == ErrWSAlreadyOpen {
|
||||
s.log(LogInformational, "Websocket already exists, no need to reconnect")
|
||||
return
|
||||
}
|
||||
|
||||
s.log(LogError, "error reconnecting to gateway, %s", err)
|
||||
|
||||
<-time.After(wait * time.Second)
|
||||
|
2
vendor/manifest
vendored
2
vendor/manifest
vendored
@ -61,7 +61,7 @@
|
||||
"importpath": "github.com/bwmarrin/discordgo",
|
||||
"repository": "https://github.com/bwmarrin/discordgo",
|
||||
"vcs": "git",
|
||||
"revision": "d420e28024ad527390b43aa7f64e029083e11989",
|
||||
"revision": "2fda7ce223a66a5b70b66987c22c3c94d022ee66",
|
||||
"branch": "master",
|
||||
"notests": true
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user