Update dependencies and build to go1.22 (#2113)

* Update dependencies and build to go1.22

* Fix api changes wrt to dependencies

* Update golangci config
This commit is contained in:
Wim
2024-05-23 23:44:31 +02:00
committed by GitHub
parent 56e7bd01ca
commit 2f33fe86f5
1556 changed files with 3279522 additions and 1924375 deletions

View File

@@ -132,10 +132,10 @@ type ComponentEmoji struct {
// Button represents button component.
type Button struct {
Label string `json:"label"`
Style ButtonStyle `json:"style"`
Disabled bool `json:"disabled"`
Emoji ComponentEmoji `json:"emoji"`
Label string `json:"label"`
Style ButtonStyle `json:"style"`
Disabled bool `json:"disabled"`
Emoji *ComponentEmoji `json:"emoji,omitempty"`
// NOTE: Only button with LinkButton style can have link. Also, URL is mutually exclusive with CustomID.
URL string `json:"url,omitempty"`
@@ -166,14 +166,32 @@ func (Button) Type() ComponentType {
// SelectMenuOption represents an option for a select menu.
type SelectMenuOption struct {
Label string `json:"label,omitempty"`
Value string `json:"value"`
Description string `json:"description"`
Emoji ComponentEmoji `json:"emoji"`
Label string `json:"label,omitempty"`
Value string `json:"value"`
Description string `json:"description"`
Emoji *ComponentEmoji `json:"emoji,omitempty"`
// Determines whenever option is selected by default or not.
Default bool `json:"default"`
}
// SelectMenuDefaultValueType represents the type of an entity selected by default in auto-populated select menus.
type SelectMenuDefaultValueType string
// SelectMenuDefaultValue types.
const (
SelectMenuDefaultValueUser SelectMenuDefaultValueType = "user"
SelectMenuDefaultValueRole SelectMenuDefaultValueType = "role"
SelectMenuDefaultValueChannel SelectMenuDefaultValueType = "channel"
)
// SelectMenuDefaultValue represents an entity selected by default in auto-populated select menus.
type SelectMenuDefaultValue struct {
// ID of the entity.
ID string `json:"id"`
// Type of the entity.
Type SelectMenuDefaultValueType `json:"type"`
}
// SelectMenuType represents select menu type.
type SelectMenuType ComponentType
@@ -198,9 +216,13 @@ type SelectMenu struct {
MinValues *int `json:"min_values,omitempty"`
// This value determines the maximal amount of selected items in the menu.
// If MaxValues or MinValues are greater than one then the user can select multiple items in the component.
MaxValues int `json:"max_values,omitempty"`
Options []SelectMenuOption `json:"options,omitempty"`
Disabled bool `json:"disabled"`
MaxValues int `json:"max_values,omitempty"`
// List of default values for auto-populated select menus.
// NOTE: Number of entries should be in the range defined by MinValues and MaxValues.
DefaultValues []SelectMenuDefaultValue `json:"default_values,omitempty"`
Options []SelectMenuOption `json:"options,omitempty"`
Disabled bool `json:"disabled"`
// NOTE: Can only be used in SelectMenu with Channel menu type.
ChannelTypes []ChannelType `json:"channel_types,omitempty"`

View File

@@ -22,7 +22,7 @@ import (
)
// VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/)
const VERSION = "0.27.1"
const VERSION = "0.28.1"
// New creates a new Discord session with provided token.
// If the token is for a bot, it must be prefixed with "Bot "
@@ -33,20 +33,21 @@ func New(token string) (s *Session, err error) {
// Create an empty Session interface.
s = &Session{
State: NewState(),
Ratelimiter: NewRatelimiter(),
StateEnabled: true,
Compress: true,
ShouldReconnectOnError: true,
ShouldRetryOnRateLimit: true,
ShardID: 0,
ShardCount: 1,
MaxRestRetries: 3,
Client: &http.Client{Timeout: (20 * time.Second)},
Dialer: websocket.DefaultDialer,
UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
sequence: new(int64),
LastHeartbeatAck: time.Now().UTC(),
State: NewState(),
Ratelimiter: NewRatelimiter(),
StateEnabled: true,
Compress: true,
ShouldReconnectOnError: true,
ShouldReconnectVoiceOnSessionError: true,
ShouldRetryOnRateLimit: true,
ShardID: 0,
ShardCount: 1,
MaxRestRetries: 3,
Client: &http.Client{Timeout: (20 * time.Second)},
Dialer: websocket.DefaultDialer,
UserAgent: "DiscordBot (https://github.com/bwmarrin/discordgo, v" + VERSION + ")",
sequence: new(int64),
LastHeartbeatAck: time.Now().UTC(),
}
// Initialize the Identify Package with defaults

View File

@@ -42,6 +42,7 @@ var (
EndpointCDNChannelIcons = EndpointCDN + "channel-icons/"
EndpointCDNBanners = EndpointCDN + "banners/"
EndpointCDNGuilds = EndpointCDN + "guilds/"
EndpointCDNRoleIcons = EndpointCDN + "role-icons/"
EndpointVoice = EndpointAPI + "/voice/"
EndpointVoiceRegions = EndpointVoice + "regions"
@@ -49,9 +50,8 @@ var (
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" }
EndpointDefaultUserAvatar = func(uDiscriminator string) string {
uDiscriminatorInt, _ := strconv.Atoi(uDiscriminator)
return EndpointCDN + "embed/avatars/" + strconv.Itoa(uDiscriminatorInt%5) + ".png"
EndpointDefaultUserAvatar = func(idx int) string {
return EndpointCDN + "embed/avatars/" + strconv.Itoa(idx) + ".png"
}
EndpointUserBanner = func(uID, cID string) string {
return EndpointCDNBanners + uID + "/" + cID + ".png"
@@ -104,7 +104,8 @@ var (
EndpointGuildScheduledEvents = func(gID string) string { return EndpointGuilds + gID + "/scheduled-events" }
EndpointGuildScheduledEvent = func(gID, eID string) string { return EndpointGuilds + gID + "/scheduled-events/" + eID }
EndpointGuildScheduledEventUsers = func(gID, eID string) string { return EndpointGuildScheduledEvent(gID, eID) + "/users" }
EndpointGuildTemplate = func(tID string) string { return EndpointGuilds + "/templates/" + tID }
EndpointGuildOnboarding = func(gID string) string { return EndpointGuilds + gID + "/onboarding" }
EndpointGuildTemplate = func(tID string) string { return EndpointGuilds + "templates/" + tID }
EndpointGuildTemplates = func(gID string) string { return EndpointGuilds + gID + "/templates" }
EndpointGuildTemplateSync = func(gID, tID string) string { return EndpointGuilds + gID + "/templates/" + tID }
EndpointGuildMemberAvatar = func(gId, uID, aID string) string {
@@ -114,6 +115,10 @@ var (
return EndpointCDNGuilds + gId + "/users/" + uID + "/avatars/" + aID + ".gif"
}
EndpointRoleIcon = func(rID, hash string) string {
return EndpointCDNRoleIcons + rID + "/" + hash + ".png"
}
EndpointChannel = func(cID string) string { return EndpointChannels + cID }
EndpointChannelThreads = func(cID string) string { return EndpointChannel(cID) + "/threads" }
EndpointChannelActiveThreads = func(cID string) string { return EndpointChannelThreads(cID) + "/active" }

View File

@@ -19,6 +19,7 @@ const (
connectEventType = "__CONNECT__"
disconnectEventType = "__DISCONNECT__"
eventEventType = "__EVENT__"
guildAuditLogEntryCreateEventType = "GUILD_AUDIT_LOG_ENTRY_CREATE"
guildBanAddEventType = "GUILD_BAN_ADD"
guildBanRemoveEventType = "GUILD_BAN_REMOVE"
guildCreateEventType = "GUILD_CREATE"
@@ -294,6 +295,26 @@ func (eh eventEventHandler) Handle(s *Session, i interface{}) {
}
}
// guildAuditLogEntryCreateEventHandler is an event handler for GuildAuditLogEntryCreate events.
type guildAuditLogEntryCreateEventHandler func(*Session, *GuildAuditLogEntryCreate)
// Type returns the event type for GuildAuditLogEntryCreate events.
func (eh guildAuditLogEntryCreateEventHandler) Type() string {
return guildAuditLogEntryCreateEventType
}
// New returns a new instance of GuildAuditLogEntryCreate.
func (eh guildAuditLogEntryCreateEventHandler) New() interface{} {
return &GuildAuditLogEntryCreate{}
}
// Handle is the handler for GuildAuditLogEntryCreate events.
func (eh guildAuditLogEntryCreateEventHandler) Handle(s *Session, i interface{}) {
if t, ok := i.(*GuildAuditLogEntryCreate); ok {
eh(s, t)
}
}
// guildBanAddEventHandler is an event handler for GuildBanAdd events.
type guildBanAddEventHandler func(*Session, *GuildBanAdd)
@@ -1277,6 +1298,8 @@ func handlerForInterface(handler interface{}) EventHandler {
return disconnectEventHandler(v)
case func(*Session, *Event):
return eventEventHandler(v)
case func(*Session, *GuildAuditLogEntryCreate):
return guildAuditLogEntryCreateEventHandler(v)
case func(*Session, *GuildBanAdd):
return guildBanAddEventHandler(v)
case func(*Session, *GuildBanRemove):
@@ -1388,6 +1411,7 @@ func init() {
registerInterfaceProvider(channelDeleteEventHandler(nil))
registerInterfaceProvider(channelPinsUpdateEventHandler(nil))
registerInterfaceProvider(channelUpdateEventHandler(nil))
registerInterfaceProvider(guildAuditLogEntryCreateEventHandler(nil))
registerInterfaceProvider(guildBanAddEventHandler(nil))
registerInterfaceProvider(guildBanRemoveEventHandler(nil))
registerInterfaceProvider(guildCreateEventHandler(nil))

View File

@@ -401,3 +401,8 @@ type AutoModerationActionExecution struct {
MatchedKeyword string `json:"matched_keyword"`
MatchedContent string `json:"matched_content"`
}
// GuildAuditLogEntryCreate is the data for a GuildAuditLogEntryCreate event.
type GuildAuditLogEntryCreate struct {
*AuditLogEntry
}

View File

@@ -314,9 +314,10 @@ type InteractionData interface {
// ApplicationCommandInteractionData contains the data of application command interaction.
type ApplicationCommandInteractionData struct {
ID string `json:"id"`
Name string `json:"name"`
Resolved *ApplicationCommandInteractionDataResolved `json:"resolved"`
ID string `json:"id"`
Name string `json:"name"`
CommandType ApplicationCommandType `json:"type"`
Resolved *ApplicationCommandInteractionDataResolved `json:"resolved"`
// Slash command options
Options []*ApplicationCommandInteractionDataOption `json:"options"`
@@ -553,6 +554,7 @@ type InteractionResponseData struct {
Embeds []*MessageEmbed `json:"embeds"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Files []*File `json:"-"`
Attachments *[]*MessageAttachment `json:"attachments,omitempty"`
// NOTE: only MessageFlagsSuppressEmbeds and MessageFlagsEphemeral can be set.
Flags MessageFlags `json:"flags,omitempty"`

View File

@@ -39,6 +39,7 @@ const (
Romanian Locale = "ro"
Russian Locale = "ru"
SpanishES Locale = "es-ES"
SpanishLATAM Locale = "es-419"
Swedish Locale = "sv-SE"
Thai Locale = "th"
Turkish Locale = "tr"
@@ -74,6 +75,7 @@ var Locales = map[Locale]string{
Romanian: "Romanian",
Russian: "Russian",
SpanishES: "Spanish (Spain)",
SpanishLATAM: "Spanish (LATAM)",
Swedish: "Swedish",
Thai: "Thai",
Turkish: "Turkish",

View File

@@ -148,8 +148,8 @@ type Message struct {
// The thread that was started from this message, includes thread member object
Thread *Channel `json:"thread,omitempty"`
// An array of Sticker objects, if any were sent.
StickerItems []*Sticker `json:"sticker_items"`
// An array of StickerItem objects, representing sent stickers, if there were any.
StickerItems []*StickerItem `json:"sticker_items"`
}
// UnmarshalJSON is a helper function to unmarshal the Message.
@@ -215,6 +215,10 @@ const (
MessageFlagsLoading MessageFlags = 1 << 7
// MessageFlagsFailedToMentionSomeRolesInThread this message failed to mention some roles and add their members to the thread.
MessageFlagsFailedToMentionSomeRolesInThread MessageFlags = 1 << 8
// MessageFlagsSuppressNotifications this message will not trigger push and desktop notifications.
MessageFlagsSuppressNotifications MessageFlags = 1 << 12
// MessageFlagsIsVoiceMessage this message is a voice message.
MessageFlagsIsVoiceMessage MessageFlags = 1 << 13
)
// File stores info about files you e.g. send in messages.
@@ -233,6 +237,8 @@ type MessageSend struct {
Files []*File `json:"-"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Reference *MessageReference `json:"message_reference,omitempty"`
StickerIDs []string `json:"sticker_ids"`
Flags MessageFlags `json:"flags,omitempty"`
// TODO: Remove this when compatibility is not required.
File *File `json:"-"`
@@ -245,8 +251,8 @@ type MessageSend struct {
// is also where you should get the instance from.
type MessageEdit struct {
Content *string `json:"content,omitempty"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds"`
Components *[]MessageComponent `json:"components,omitempty"`
Embeds *[]*MessageEmbed `json:"embeds,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
Flags MessageFlags `json:"flags,omitempty"`
// Files to append to the message
@@ -280,14 +286,14 @@ func (m *MessageEdit) SetContent(str string) *MessageEdit {
// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
m.Embeds = []*MessageEmbed{embed}
m.Embeds = &[]*MessageEmbed{embed}
return m
}
// SetEmbeds is a convenience function for setting the embeds,
// so you can chain commands.
func (m *MessageEdit) SetEmbeds(embeds []*MessageEmbed) *MessageEdit {
m.Embeds = embeds
m.Embeds = &embeds
return m
}
@@ -460,20 +466,32 @@ type MessageApplication struct {
// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
MessageID string `json:"message_id"`
ChannelID string `json:"channel_id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
MessageID string `json:"message_id"`
ChannelID string `json:"channel_id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
FailIfNotExists *bool `json:"fail_if_not_exists,omitempty"`
}
// Reference returns MessageReference of given message
func (m *Message) Reference() *MessageReference {
func (m *Message) reference(failIfNotExists bool) *MessageReference {
return &MessageReference{
GuildID: m.GuildID,
ChannelID: m.ChannelID,
MessageID: m.ID,
GuildID: m.GuildID,
ChannelID: m.ChannelID,
MessageID: m.ID,
FailIfNotExists: &failIfNotExists,
}
}
// Reference returns a MessageReference of the given message.
func (m *Message) Reference() *MessageReference {
return m.reference(true)
}
// SoftReference returns a MessageReference of the given message.
// If the message doesn't exist it will instead be sent as a non-reply message.
func (m *Message) SoftReference() *MessageReference {
return m.reference(false)
}
// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {

View File

@@ -424,10 +424,11 @@ func (s *Session) UserGuildMember(guildID string, options ...RequestOption) (st
}
// UserGuilds returns an array of UserGuild structures for all guilds.
// limit : The number guilds that can be returned. (max 100)
// beforeID : If provided all guilds returned will be before given ID.
// afterID : If provided all guilds returned will be after given ID.
func (s *Session) UserGuilds(limit int, beforeID, afterID string, options ...RequestOption) (st []*UserGuild, err error) {
// limit : The number guilds that can be returned. (max 200)
// beforeID : If provided all guilds returned will be before given ID.
// afterID : If provided all guilds returned will be after given ID.
// withCounts : Whether to include approximate member and presence counts or not.
func (s *Session) UserGuilds(limit int, beforeID, afterID string, withCounts bool, options ...RequestOption) (st []*UserGuild, err error) {
v := url.Values{}
@@ -440,6 +441,9 @@ func (s *Session) UserGuilds(limit int, beforeID, afterID string, options ...Req
if beforeID != "" {
v.Set("before", beforeID)
}
if withCounts {
v.Set("with_counts", "true")
}
uri := EndpointUserGuilds("@me")
@@ -672,14 +676,9 @@ func (s *Session) GuildEdit(guildID string, g *GuildParams, options ...RequestOp
// GuildDelete deletes a Guild.
// guildID : The ID of a Guild
func (s *Session) GuildDelete(guildID string, options ...RequestOption) (st *Guild, err error) {
func (s *Session) GuildDelete(guildID string, options ...RequestOption) (err error) {
body, err := s.RequestWithBucketID("DELETE", EndpointGuild(guildID), nil, EndpointGuild(guildID), options...)
if err != nil {
return
}
err = unmarshal(body, &st)
_, err = s.RequestWithBucketID("DELETE", EndpointGuild(guildID), nil, EndpointGuild(guildID), options...)
return
}
@@ -1700,13 +1699,19 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend,
}
}
if data.StickerIDs != nil {
if len(data.StickerIDs) > 3 {
err = fmt.Errorf("cannot send more than 3 stickers")
return
}
}
var response []byte
if len(files) > 0 {
contentType, body, encodeErr := MultipartBodyWithJSON(data, files)
if encodeErr != nil {
return st, encodeErr
}
response, err = s.request("POST", endpoint, contentType, body, endpoint, 0, options...)
} else {
response, err = s.RequestWithBucketID("POST", endpoint, data, endpoint, options...)
@@ -1796,16 +1801,18 @@ func (s *Session) ChannelMessageEditComplex(m *MessageEdit, options ...RequestOp
// TODO: Remove this when compatibility is not required.
if m.Embed != nil {
if m.Embeds == nil {
m.Embeds = []*MessageEmbed{m.Embed}
m.Embeds = &[]*MessageEmbed{m.Embed}
} else {
err = fmt.Errorf("cannot specify both Embed and Embeds")
return
}
}
for _, embed := range m.Embeds {
if embed.Type == "" {
embed.Type = "rich"
if m.Embeds != nil {
for _, embed := range *m.Embeds {
if embed.Type == "" {
embed.Type = "rich"
}
}
}
@@ -2267,7 +2274,7 @@ func (s *Session) WebhookWithToken(webhookID, token string, options ...RequestOp
// webhookID: The ID of a webhook.
// name : The name of the webhook.
// avatar : The avatar of the webhook.
func (s *Session) WebhookEdit(webhookID, name, avatar, channelID string, options ...RequestOption) (st *Role, err error) {
func (s *Session) WebhookEdit(webhookID, name, avatar, channelID string, options ...RequestOption) (st *Webhook, err error) {
data := struct {
Name string `json:"name,omitempty"`
@@ -2290,14 +2297,15 @@ func (s *Session) WebhookEdit(webhookID, name, avatar, channelID string, options
// token : The auth token for the webhook.
// name : The name of the webhook.
// avatar : The avatar of the webhook.
func (s *Session) WebhookEditWithToken(webhookID, token, name, avatar string, options ...RequestOption) (st *Role, err error) {
func (s *Session) WebhookEditWithToken(webhookID, token, name, avatar string, options ...RequestOption) (st *Webhook, err error) {
data := struct {
Name string `json:"name,omitempty"`
Avatar string `json:"avatar,omitempty"`
}{name, avatar}
body, err := s.RequestWithBucketID("PATCH", EndpointWebhookToken(webhookID, token), data, EndpointWebhookToken("", ""), options...)
var body []byte
body, err = s.RequestWithBucketID("PATCH", EndpointWebhookToken(webhookID, token), data, EndpointWebhookToken("", ""), options...)
if err != nil {
return
}
@@ -2709,11 +2717,22 @@ func (s *Session) ThreadMemberRemove(threadID, memberID string, options ...Reque
return err
}
// ThreadMember returns thread member object for the specified member of a thread
func (s *Session) ThreadMember(threadID, memberID string, options ...RequestOption) (member *ThreadMember, err error) {
endpoint := EndpointThreadMember(threadID, memberID)
// ThreadMember returns thread member object for the specified member of a thread.
// withMember : Whether to include a guild member object.
func (s *Session) ThreadMember(threadID, memberID string, withMember bool, options ...RequestOption) (member *ThreadMember, err error) {
uri := EndpointThreadMember(threadID, memberID)
queryParams := url.Values{}
if withMember {
queryParams.Set("with_member", "true")
}
if len(queryParams) > 0 {
uri += "?" + queryParams.Encode()
}
var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint, options...)
body, err = s.RequestWithBucketID("GET", uri, nil, uri, options...)
if err != nil {
return
@@ -2724,9 +2743,29 @@ func (s *Session) ThreadMember(threadID, memberID string, options ...RequestOpti
}
// ThreadMembers returns all members of specified thread.
func (s *Session) ThreadMembers(threadID string, options ...RequestOption) (members []*ThreadMember, err error) {
// limit : Max number of thread members to return (1-100). Defaults to 100.
// afterID : Get thread members after this user ID.
// withMember : Whether to include a guild member object for each thread member.
func (s *Session) ThreadMembers(threadID string, limit int, withMember bool, afterID string, options ...RequestOption) (members []*ThreadMember, err error) {
uri := EndpointThreadMembers(threadID)
queryParams := url.Values{}
if withMember {
queryParams.Set("with_member", "true")
}
if limit > 0 {
queryParams.Set("limit", strconv.Itoa(limit))
}
if afterID != "" {
queryParams.Set("after", afterID)
}
if len(queryParams) > 0 {
uri += "?" + queryParams.Encode()
}
var body []byte
body, err = s.RequestWithBucketID("GET", EndpointThreadMembers(threadID), nil, EndpointThreadMembers(threadID), options...)
body, err = s.RequestWithBucketID("GET", uri, nil, uri, options...)
if err != nil {
return
@@ -3248,6 +3287,37 @@ func (s *Session) GuildScheduledEventUsers(guildID, eventID string, limit int, w
return
}
// GuildOnboarding returns onboarding configuration of a guild.
// guildID : The ID of the guild
func (s *Session) GuildOnboarding(guildID string, options ...RequestOption) (onboarding *GuildOnboarding, err error) {
endpoint := EndpointGuildOnboarding(guildID)
var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint, options...)
if err != nil {
return
}
err = unmarshal(body, &onboarding)
return
}
// GuildOnboardingEdit edits onboarding configuration of a guild.
// guildID : The ID of the guild
// o : New GuildOnboarding data
func (s *Session) GuildOnboardingEdit(guildID string, o *GuildOnboarding, options ...RequestOption) (onboarding *GuildOnboarding, err error) {
endpoint := EndpointGuildOnboarding(guildID)
var body []byte
body, err = s.RequestWithBucketID("PUT", endpoint, o, endpoint, options...)
if err != nil {
return
}
err = unmarshal(body, &onboarding)
return
}
// ----------------------------------------------------------------------
// Functions specific to auto moderation
// ----------------------------------------------------------------------

View File

@@ -42,6 +42,9 @@ type Session struct {
// Should the session reconnect the websocket on errors.
ShouldReconnectOnError bool
// Should voice connections reconnect on a session reconnect.
ShouldReconnectVoiceOnSessionError bool
// Should the session retry requests when rate limited.
ShouldRetryOnRateLimit bool
@@ -285,7 +288,9 @@ const (
ChannelTypeGuildPublicThread ChannelType = 11
ChannelTypeGuildPrivateThread ChannelType = 12
ChannelTypeGuildStageVoice ChannelType = 13
ChannelTypeGuildDirectory ChannelType = 14
ChannelTypeGuildForum ChannelType = 15
ChannelTypeGuildMedia ChannelType = 16
)
// ChannelFlags represent flags of a channel/thread.
@@ -440,7 +445,7 @@ type ChannelEdit struct {
Name string `json:"name,omitempty"`
Topic string `json:"topic,omitempty"`
NSFW *bool `json:"nsfw,omitempty"`
Position int `json:"position"`
Position *int `json:"position,omitempty"`
Bitrate int `json:"bitrate,omitempty"`
UserLimit int `json:"user_limit,omitempty"`
PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites,omitempty"`
@@ -528,6 +533,10 @@ type ThreadMember struct {
JoinTimestamp time.Time `json:"join_timestamp"`
// Any user-thread settings, currently only used for notifications
Flags int `json:"flags"`
// Additional information about the user.
// NOTE: only present if the withMember parameter is set to true
// when calling Session.ThreadMembers or Session.ThreadMember.
Member *Member `json:"member,omitempty"`
}
// ThreadsList represents a list of threads alongisde with thread member objects for the current user.
@@ -649,6 +658,13 @@ type Sticker struct {
SortValue int `json:"sort_value"`
}
// StickerItem represents the smallest amount of data required to render a sticker. A partial sticker object.
type StickerItem struct {
ID string `json:"id"`
Name string `json:"name"`
FormatType StickerFormat `json:"format_type"`
}
// StickerPack represents a pack of standard stickers.
type StickerPack struct {
ID string `json:"id"`
@@ -1067,6 +1083,109 @@ type GuildScheduledEventUser struct {
Member *Member `json:"member"`
}
// GuildOnboardingMode defines the criteria used to satisfy constraints that are required for enabling onboarding.
// https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-mode
type GuildOnboardingMode int
// Block containing known GuildOnboardingMode values.
const (
// GuildOnboardingModeDefault counts default channels towards constraints.
GuildOnboardingModeDefault GuildOnboardingMode = 0
// GuildOnboardingModeAdvanced counts default channels and questions towards constraints.
GuildOnboardingModeAdvanced GuildOnboardingMode = 1
)
// GuildOnboarding represents the onboarding flow for a guild.
// https://discord.com/developers/docs/resources/guild#guild-onboarding-object
type GuildOnboarding struct {
// ID of the guild this onboarding flow is part of.
GuildID string `json:"guild_id,omitempty"`
// Prompts shown during onboarding and in the customize community (Channels & Roles) tab.
Prompts *[]GuildOnboardingPrompt `json:"prompts,omitempty"`
// Channel IDs that members get opted into automatically.
DefaultChannelIDs []string `json:"default_channel_ids,omitempty"`
// Whether onboarding is enabled in the guild.
Enabled *bool `json:"enabled,omitempty"`
// Mode of onboarding.
Mode *GuildOnboardingMode `json:"mode,omitempty"`
}
// GuildOnboardingPromptType is the type of an onboarding prompt.
// https://discord.com/developers/docs/resources/guild#guild-onboarding-object-prompt-types
type GuildOnboardingPromptType int
// Block containing known GuildOnboardingPromptType values.
const (
GuildOnboardingPromptTypeMultipleChoice GuildOnboardingPromptType = 0
GuildOnboardingPromptTypeDropdown GuildOnboardingPromptType = 1
)
// GuildOnboardingPrompt is a prompt shown during onboarding and in the customize community (Channels & Roles) tab.
// https://discord.com/developers/docs/resources/guild#guild-onboarding-object-onboarding-prompt-structure
type GuildOnboardingPrompt struct {
// ID of the prompt.
// NOTE: always requires to be a valid snowflake (e.g. "0"), see
// https://github.com/discord/discord-api-docs/issues/6320 for more information.
ID string `json:"id,omitempty"`
// Type of the prompt.
Type GuildOnboardingPromptType `json:"type"`
// Options available within the prompt.
Options []GuildOnboardingPromptOption `json:"options"`
// Title of the prompt.
Title string `json:"title"`
// Indicates whether users are limited to selecting one option for the prompt.
SingleSelect bool `json:"single_select"`
// Indicates whether the prompt is required before a user completes the onboarding flow.
Required bool `json:"required"`
// Indicates whether the prompt is present in the onboarding flow.
// If false, the prompt will only appear in the customize community (Channels & Roles) tab.
InOnboarding bool `json:"in_onboarding"`
}
// GuildOnboardingPromptOption is an option available within an onboarding prompt.
// https://discord.com/developers/docs/resources/guild#guild-onboarding-object-prompt-option-structure
type GuildOnboardingPromptOption struct {
// ID of the prompt option.
ID string `json:"id,omitempty"`
// IDs for channels a member is added to when the option is selected.
ChannelIDs []string `json:"channel_ids"`
// IDs for roles assigned to a member when the option is selected.
RoleIDs []string `json:"role_ids"`
// Emoji of the option.
// NOTE: when creating or updating a prompt option
// EmojiID, EmojiName and EmojiAnimated should be used instead.
Emoji *Emoji `json:"emoji,omitempty"`
// Title of the option.
Title string `json:"title"`
// Description of the option.
Description string `json:"description"`
// ID of the option's emoji.
// NOTE: only used when creating or updating a prompt option.
EmojiID string `json:"emoji_id,omitempty"`
// Name of the option's emoji.
// NOTE: only used when creating or updating a prompt option.
EmojiName string `json:"emoji_name,omitempty"`
// Whether the option's emoji is animated.
// NOTE: only used when creating or updating a prompt option.
EmojiAnimated *bool `json:"emoji_animated,omitempty"`
}
// A GuildTemplate represents a replicable template for guild creation
type GuildTemplate struct {
// The unique code for the guild template
@@ -1157,6 +1276,14 @@ type UserGuild struct {
Owner bool `json:"owner"`
Permissions int64 `json:"permissions,string"`
Features []GuildFeature `json:"features"`
// Approximate number of members in this guild.
// NOTE: this field is only filled when withCounts is true.
ApproximateMemberCount int `json:"approximate_member_count"`
// Approximate number of non-offline members in this guild.
// NOTE: this field is only filled when withCounts is true.
ApproximatePresenceCount int `json:"approximate_presence_count"`
}
// GuildFeature indicates the presence of a feature in a guild
@@ -1239,13 +1366,51 @@ type Role struct {
// This is a combination of bit masks; the presence of a certain permission can
// be checked by performing a bitwise AND between this int and the permission.
Permissions int64 `json:"permissions,string"`
// The hash of the role icon. Use Role.IconURL to retrieve the icon's URL.
Icon string `json:"icon"`
// The emoji assigned to this role.
UnicodeEmoji string `json:"unicode_emoji"`
// The flags of the role, which describe its extra features.
// This is a combination of bit masks; the presence of a certain flag can
// be checked by performing a bitwise AND between this int and the flag.
Flags RoleFlags `json:"flags"`
}
// RoleFlags represent the flags of a Role.
// https://discord.com/developers/docs/topics/permissions#role-object-role-flags
type RoleFlags int
// Block containing known RoleFlags values.
const (
// RoleFlagInPrompt indicates whether the Role is selectable by members in an onboarding prompt.
RoleFlagInPrompt RoleFlags = 1 << 0
)
// Mention returns a string which mentions the role
func (r *Role) Mention() string {
return fmt.Sprintf("<@&%s>", r.ID)
}
// IconURL returns the URL of the role's icon.
//
// size: The size of the desired role icon as a power of two
// Image size can be any power of two between 16 and 4096.
func (r *Role) IconURL(size string) string {
if r.Icon == "" {
return ""
}
URL := EndpointRoleIcon(r.ID, r.Icon)
if size != "" {
return URL + "?size=" + size
}
return URL
}
// RoleParams represents the parameters needed to create or update a Role
type RoleParams struct {
// The role's name
@@ -1258,6 +1423,12 @@ type RoleParams struct {
Permissions *int64 `json:"permissions,omitempty,string"`
// Whether this role is mentionable
Mentionable *bool `json:"mentionable,omitempty"`
// The role's unicode emoji.
// NOTE: can only be set if the guild has the ROLE_ICONS feature.
UnicodeEmoji *string `json:"unicode_emoji,omitempty"`
// The role's icon image encoded in base64.
// NOTE: can only be set if the guild has the ROLE_ICONS feature.
Icon *string `json:"icon,omitempty"`
}
// Roles are a collection of Role
@@ -1330,6 +1501,22 @@ type Assets struct {
SmallText string `json:"small_text,omitempty"`
}
// MemberFlags represent flags of a guild member.
// https://discord.com/developers/docs/resources/guild#guild-member-object-guild-member-flags
type MemberFlags int
// Block containing known MemberFlags values.
const (
// MemberFlagDidRejoin indicates whether the Member has left and rejoined the guild.
MemberFlagDidRejoin MemberFlags = 1 << 0
// MemberFlagCompletedOnboarding indicates whether the Member has completed onboarding.
MemberFlagCompletedOnboarding MemberFlags = 1 << 1
// MemberFlagBypassesVerification indicates whether the Member is exempt from guild verification requirements.
MemberFlagBypassesVerification MemberFlags = 1 << 2
// MemberFlagStartedOnboarding indicates whether the Member has started onboarding.
MemberFlagStartedOnboarding MemberFlags = 1 << 3
)
// A Member stores user information for Guild members. A guild
// member represents a certain user's presence in a guild.
type Member struct {
@@ -1360,6 +1547,10 @@ type Member struct {
// When the user used their Nitro boost on the server
PremiumSince *time.Time `json:"premium_since"`
// The flags of this member. This is a combination of bit masks; the presence of a certain
// flag can be checked by performing a bitwise AND between this int and the flag.
Flags MemberFlags `json:"flags"`
// Is true while the member hasn't accepted the membership screen.
Pending bool `json:"pending"`
@@ -1391,6 +1582,15 @@ func (m *Member) AvatarURL(size string) string {
}
// DisplayName returns the member's guild nickname if they have one,
// otherwise it returns their discord display name.
func (m *Member) DisplayName() string {
if m.Nick != "" {
return m.Nick
}
return m.User.GlobalName
}
// ClientStatus stores the online, offline, idle, or dnd status of each device of a Guild member.
type ClientStatus struct {
Desktop Status `json:"desktop"`
@@ -1738,14 +1938,18 @@ const (
// AuditLogOptions optional data for the AuditLog
// https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object-optional-audit-entry-info
type AuditLogOptions struct {
DeleteMemberDays string `json:"delete_member_days"`
MembersRemoved string `json:"members_removed"`
ChannelID string `json:"channel_id"`
MessageID string `json:"message_id"`
Count string `json:"count"`
ID string `json:"id"`
Type *AuditLogOptionsType `json:"type"`
RoleName string `json:"role_name"`
DeleteMemberDays string `json:"delete_member_days"`
MembersRemoved string `json:"members_removed"`
ChannelID string `json:"channel_id"`
MessageID string `json:"message_id"`
Count string `json:"count"`
ID string `json:"id"`
Type *AuditLogOptionsType `json:"type"`
RoleName string `json:"role_name"`
ApplicationID string `json:"application_id"`
AutoModerationRuleName string `json:"auto_moderation_rule_name"`
AutoModerationRuleTriggerType string `json:"auto_moderation_rule_trigger_type"`
IntegrationType string `json:"integration_type"`
}
// AuditLogOptionsType of the AuditLogOption
@@ -1754,8 +1958,8 @@ type AuditLogOptionsType string
// Valid Types for AuditLogOptionsType
const (
AuditLogOptionsTypeMember AuditLogOptionsType = "member"
AuditLogOptionsTypeRole AuditLogOptionsType = "role"
AuditLogOptionsTypeRole AuditLogOptionsType = "0"
AuditLogOptionsTypeMember AuditLogOptionsType = "1"
)
// AuditLogAction is the Action of the AuditLog (see AuditLogAction* consts)
@@ -1816,7 +2020,7 @@ const (
AuditLogActionStickerDelete AuditLogAction = 92
AuditLogGuildScheduledEventCreate AuditLogAction = 100
AuditLogGuildScheduledEventUpdare AuditLogAction = 101
AuditLogGuildScheduledEventUpdate AuditLogAction = 101
AuditLogGuildScheduledEventDelete AuditLogAction = 102
AuditLogActionThreadCreate AuditLogAction = 110
@@ -1824,6 +2028,16 @@ const (
AuditLogActionThreadDelete AuditLogAction = 112
AuditLogActionApplicationCommandPermissionUpdate AuditLogAction = 121
AuditLogActionAutoModerationRuleCreate AuditLogAction = 140
AuditLogActionAutoModerationRuleUpdate AuditLogAction = 141
AuditLogActionAutoModerationRuleDelete AuditLogAction = 142
AuditLogActionAutoModerationBlockMessage AuditLogAction = 143
AuditLogActionAutoModerationFlagToChannel AuditLogAction = 144
AuditLogActionAutoModerationUserCommunicationDisabled AuditLogAction = 145
AuditLogActionCreatorMonetizationRequestCreated AuditLogAction = 150
AuditLogActionCreatorMonetizationTermsAccepted AuditLogAction = 151
)
// GuildMemberParams stores data needed to update a member
@@ -2341,6 +2555,9 @@ const (
ErrCodeCannotUpdateAFinishedEvent = 180000
ErrCodeFailedToCreateStageNeededForStageEvent = 180002
ErrCodeCannotEnableOnboardingRequirementsAreNotMet = 350000
ErrCodeCannotUpdateOnboardingWhileBelowRequirements = 350001
)
// Intent is the type of a Gateway Intent
@@ -2351,7 +2568,7 @@ type Intent int
const (
IntentGuilds Intent = 1 << 0
IntentGuildMembers Intent = 1 << 1
IntentGuildBans Intent = 1 << 2
IntentGuildModeration Intent = 1 << 2
IntentGuildEmojis Intent = 1 << 3
IntentGuildIntegrations Intent = 1 << 4
IntentGuildWebhooks Intent = 1 << 5
@@ -2371,6 +2588,8 @@ const (
// TODO: remove when compatibility is not needed
IntentGuildBans Intent = IntentGuildModeration
IntentsGuilds Intent = 1 << 0
IntentsGuildMembers Intent = 1 << 1
IntentsGuildBans Intent = 1 << 2

View File

@@ -1,5 +1,9 @@
package discordgo
import (
"strconv"
)
// UserFlags is the flags of "user" (see UserFlags* consts)
// https://discord.com/developers/docs/resources/user#user-object-user-flags
type UserFlags int
@@ -20,6 +24,20 @@ const (
UserFlagVerifiedBot UserFlags = 1 << 16
UserFlagVerifiedBotDeveloper UserFlags = 1 << 17
UserFlagDiscordCertifiedModerator UserFlags = 1 << 18
UserFlagBotHTTPInteractions UserFlags = 1 << 19
UserFlagActiveBotDeveloper UserFlags = 1 << 22
)
// UserPremiumType is the type of premium (nitro) subscription a user has (see UserPremiumType* consts).
// https://discord.com/developers/docs/resources/user#user-object-premium-types
type UserPremiumType int
// Valid UserPremiumType values.
const (
UserPremiumTypeNone UserPremiumType = 0
UserPremiumTypeNitroClassic UserPremiumType = 1
UserPremiumTypeNitro UserPremiumType = 2
UserPremiumTypeNitroBasic UserPremiumType = 3
)
// A User stores all data for an individual Discord user.
@@ -44,6 +62,10 @@ type User struct {
// The discriminator of the user (4 numbers after name).
Discriminator string `json:"discriminator"`
// The user's display name, if it is set.
// For bots, this is the application name.
GlobalName string `json:"global_name"`
// The token of the user. This is only present for
// the user represented by the current session.
Token string `json:"token"`
@@ -70,7 +92,7 @@ type User struct {
// The type of Nitro subscription on a user's account.
// Only available when the request is authorized via a Bearer token.
PremiumType int `json:"premium_type"`
PremiumType UserPremiumType `json:"premium_type"`
// Whether the user is an Official Discord System user (part of the urgent message system).
System bool `json:"system"`
@@ -81,7 +103,14 @@ type User struct {
}
// String returns a unique identifier of the form username#discriminator
// or just username, if the discriminator is set to "0".
func (u *User) String() string {
// If the user has been migrated from the legacy username system, their discriminator is "0".
// See https://support-dev.discord.com/hc/en-us/articles/13667755828631
if u.Discriminator == "0" {
return u.Username
}
return u.Username + "#" + u.Discriminator
}
@@ -91,17 +120,35 @@ func (u *User) Mention() string {
}
// AvatarURL returns a URL to the user's avatar.
// size: The size of the user's avatar as a power of two
// if size is an empty string, no size parameter will
// be added to the URL.
//
// size: The size of the user's avatar as a power of two
// if size is an empty string, no size parameter will
// be added to the URL.
func (u *User) AvatarURL(size string) string {
return avatarURL(u.Avatar, EndpointDefaultUserAvatar(u.Discriminator),
EndpointUserAvatar(u.ID, u.Avatar), EndpointUserAvatarAnimated(u.ID, u.Avatar), size)
return avatarURL(
u.Avatar,
EndpointDefaultUserAvatar(u.DefaultAvatarIndex()),
EndpointUserAvatar(u.ID, u.Avatar),
EndpointUserAvatarAnimated(u.ID, u.Avatar),
size,
)
}
// BannerURL returns the URL of the users's banner image.
// size: The size of the desired banner image as a power of two
// Image size can be any power of two between 16 and 4096.
//
// size: The size of the desired banner image as a power of two
// Image size can be any power of two between 16 and 4096.
func (u *User) BannerURL(size string) string {
return bannerURL(u.Banner, EndpointUserBanner(u.ID, u.Banner), EndpointUserBannerAnimated(u.ID, u.Banner), size)
}
// DefaultAvatarIndex returns the index of the user's default avatar.
func (u *User) DefaultAvatarIndex() int {
if u.Discriminator == "0" {
id, _ := strconv.ParseUint(u.ID, 10, 64)
return int((id >> 22) % 6)
}
id, _ := strconv.Atoi(u.Discriminator)
return id % 5
}

View File

@@ -76,7 +76,7 @@ type VoiceSpeakingUpdateHandler func(vc *VoiceConnection, vs *VoiceSpeakingUpdat
// Speaking sends a speaking notification to Discord over the voice websocket.
// This must be sent as true prior to sending audio and should be set to false
// once finished sending audio.
// b : Send true if speaking, false if not.
// b : Send true if speaking, false if not.
func (v *VoiceConnection) Speaking(b bool) (err error) {
v.log(LogDebug, "called (%t)", b)
@@ -294,11 +294,15 @@ func (v *VoiceConnection) open() (err error) {
if v.sessionID != "" {
break
}
if i > 20 { // only loop for up to 1 second total
return fmt.Errorf("did not receive voice Session ID in time")
}
// Release the lock, so sessionID can be populated upon receiving a VoiceStateUpdate event.
v.Unlock()
time.Sleep(50 * time.Millisecond)
i++
v.Lock()
}
// Connect to VoiceConnection Websocket

View File

@@ -34,10 +34,14 @@ type WebhookParams struct {
Files []*File `json:"-"`
Components []MessageComponent `json:"components"`
Embeds []*MessageEmbed `json:"embeds,omitempty"`
Attachments []*MessageAttachment `json:"attachments,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
// Only MessageFlagsSuppressEmbeds and MessageFlagsEphemeral can be set.
// MessageFlagsEphemeral can only be set when using Followup Message Create endpoint.
Flags MessageFlags `json:"flags,omitempty"`
// Name of the thread to create.
// NOTE: can only be set if the webhook channel is a forum.
ThreadName string `json:"thread_name,omitempty"`
}
// WebhookEdit stores data for editing of a webhook message.
@@ -46,5 +50,6 @@ type WebhookEdit struct {
Components *[]MessageComponent `json:"components,omitempty"`
Embeds *[]*MessageEmbed `json:"embeds,omitempty"`
Files []*File `json:"-"`
Attachments *[]*MessageAttachment `json:"attachments,omitempty"`
AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
}

View File

@@ -389,6 +389,26 @@ func (s *Session) UpdateListeningStatus(name string) (err error) {
return s.UpdateStatusComplex(*newUpdateStatusData(0, ActivityTypeListening, name, ""))
}
// UpdateCustomStatus is used to update the user's custom status.
// If state!="" then set the custom status.
// Else, set user to active and remove the custom status.
func (s *Session) UpdateCustomStatus(state string) (err error) {
data := UpdateStatusData{
Status: "online",
}
if state != "" {
// Discord requires a non-empty activity name, therefore we provide "Custom Status" as a placeholder.
data.Activities = []*Activity{{
Name: "Custom Status",
Type: ActivityTypeCustom,
State: state,
}}
}
return s.UpdateStatusComplex(data)
}
// UpdateStatusComplex allows for sending the raw status update data untouched by discordgo.
func (s *Session) UpdateStatusComplex(usd UpdateStatusData) (err error) {
// The comment does say "untouched by discordgo", but we might need to lie a bit here.
@@ -862,17 +882,18 @@ func (s *Session) reconnect() {
// However, there seems to be cases where something "weird"
// happens. So we're doing this for now just to improve
// stability in those edge cases.
s.RLock()
defer s.RUnlock()
for _, v := range s.VoiceConnections {
if s.ShouldReconnectVoiceOnSessionError {
s.RLock()
defer s.RUnlock()
for _, v := range s.VoiceConnections {
s.log(LogInformational, "reconnecting voice connection to guild %s", v.GuildID)
go v.reconnect()
// This is here just to prevent violently spamming the
// voice reconnects
time.Sleep(1 * time.Second)
s.log(LogInformational, "reconnecting voice connection to guild %s", v.GuildID)
go v.reconnect()
// This is here just to prevent violently spamming the
// voice reconnects
time.Sleep(1 * time.Second)
}
}
return
}